初识C语言

  • 什么是C语言
    • 什么是计算机语言
    • 什么是底层开发
    • 计算机语言的发展
    • C语言概述和标准
  • 第一个C语言程序
    • 打印程序
    • 主函数的其他写法
  • 数据类型
    • C语言提供的数据类型
    • 每一个类型的大小
    • 类型的使用
  • 变量
    • 创建变量的方法
    • 变量的命名
    • 变量的分类
    • 变量的使用
    • 占位符
    • 变量的作用域和生命周期
    • 跨文件全局变量使用
  • 常量
    • 字面常量
    • const修饰的常变量
    • #define定义的标识符常量
    • 枚举常量
  • 字符串/转义字符/注释
    • 字符串
    • 转义字符表
    • ASCII码表
    • 注释
  • 分支和循环
    • if…else语句
    • while语句
    • 多组输入
  • 函数
    • 函数作用
    • 函数样例
    • 输入带空格的字符串
  • 数组
    • 什么是数组
    • 数组的创建和访问
  • 操作符
    • 算数操作符
    • 移位操作符
    • 位操作符
    • 赋值操作符
    • 单目操作符
    • 关系操作符
    • 逻辑操作符
    • 条件操作符
    • 逗号表达式
    • 下标引用, 函数调用和结构体成员访问操作符
  • 表达式求值
    • 表达式求值的要素
    • 隐式类型转换 (整型提升)
    • 整型提升是怎么进行的
    • 算数转换
    • 表达式求值顺序的影响因素
    • 操作符的优先级和结合性表 (由高到低)
  • 关键字
    • typedef
    • static
    • register
    • const
  • 宏和指针
    • #define定义的宏
    • 内存
    • 指针变量的创建和使用
    • 指针变量的大小
  • 结构体
    • 结构体的创建和使用
    • 结构体的成员访问

什么是C语言

什么是计算机语言

1. 人和人交流的语言是: 汉语/英语......2. 人和计算机交流的语言是: C语言/C++语言......3. 计算机语言就是人和计算机交流的语言

什么是底层开发


计算机语言的发展


C语言概述和标准

C语言是一门通用计算机编程语言, 广泛应用于底层开发. C语言的设计目标是提供一种能以简易的方式编译/处理低级存储器/产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言.

二十世纪八十年代, 为了避免各开发厂商用的C语言语法产生差异, 由美国国家标准局为C语言制定了一套完整的美国国家标准语法, 称为ANSIC, 作为C语言最初的标准. 目前2011年12月8日, 国际标准化组织 (ISO) 和国际电工委员会 (IEC) 发布的C11标准是C语言的第三个官方标准, 也是C语言的最新标准, 该标准更好的支持了汉字函数名和汉字标识符, 一定程度上实现了汉字编程.


第一个C语言程序

打印程序

#include //包含输入输出标准头文件int main(){printf("Hello Bit");//printf是一个库函数,功能就是在屏幕上打印数据//这里会在屏幕上打印Hello Bitreturn 0;}//C语言中main函数是程序的入口,一个工程中有且只有一个main函数//库函数--C语言编译器中提供的现成的函数//.c - 源文件 .h - 头文件

主函数的其他写法

//第一种void main(){//非常古老的写法--不推荐}//第二种int main(void){//void表示main函数不接受任何参数return 0;}//第三种int main(int argc, char* argv[]){//以后了解return 0;}

数据类型

C语言提供的数据类型

char//字符数据类型short//短整型int//整型long//长整型long long//更长的整型float//单精度浮点数double//双精度浮点数_Bool//布尔类型--C99long double//更长的双精度浮点型--C99//char是字符类型, 字符的本质是字符的ASCII码值, ASCII码值是整型,//所以字符类型在归类的时候, 是可以划分到整型家族的

每一个类型的大小

#include int main(){printf("%d\n",sizeof(char));//1printf("%d\n",sizeof(short));//2printf("%d\n",sizeof(int));//4printf("%d\n",sizeof(long));//4printf("%d\n",sizeof(long long));//8printf("%d\n",sizeof(float));//4printf("%d\n",sizeof(double));//8printf("%d\n",sizeof(_Bool));//1printf("%d\n",sizeof(long double));//8return 0;}//sizeof的作用是求大小, 单位是字节//计算机中的单位: bit--byte--kb--mb--gb--tb--pb//C语言标准规定: sizeof(long) >= sizeof(int)//sizeof(long double) >= sizeof(double)//%d--是一个占位符, 作用是以十进制的形式打印//\n--是一个转义字符, 作用是换行

类型的使用

int main(){ char ch = 'w';int weight = 120;//类型的作用就是用来创建变量//变量创建的本质是向内存中申请一块空间weight = 20;//其实是把20放在weight这块空间里, 这里使用的是weight的空间int a = weight;//其实是使用了weight中存放的值, 把weight中的20存放到a中// 左值右值//其实就是左值代表空间, 右值代表空间的内容return 0;}//机器去看内存的时候都是通过地址去访问的,变量名只是给程序员看的(方便程序员操作)

变量

创建变量的方法

int main(){//第一种//类型 变量名;int a;//第二种//类型 变量名 = 初始值;float b = 20.12f;return 0;}//小数直接写出来, 编译器默认其是double类型的值//小数后加f, 这时就是float类型的值

变量的命名

变量的命名要遵守以下规则:1. 只能由字母 (包括大写和小写) / 数字和下划线 (_) 组成2. 不能以数字开头3. 长度不能超过63个字符4. 变量名中区分大小写的5. 变量名不能使用关键字

变量的分类

#include int a = 10;//全局变量int main(){ int a = 20;//局部变量printf("%d\n", a);return 0;}//全局变量和局部变量使用时, 局部优先//原则上变量名不要冲突//静态变量和全局变量如果不初始化默认是0

变量的使用

#include //求两个整数的和int main(){int num1 = 0;int num2 = 0;//输入两个整数的值scanf("%d%d",&num1,&num2);//scanf的作用是输入数据sum1 = num1 + num2;printf("%d\n", sum1);return 0;}

以上代码有的编译器(VS2022)可能会报错, 解决方法:
1. 在源文件的第一行添加: #define _CRT_SECURE_NO_WARNINGS 1
2. 替换scanf函数为: scanf_s
VS的一劳永逸解决方法:
1. 找到VS安装路径下的newc++file.cpp的文件
2. 在这个文件中添加: #define _CRT_SECURE_NO_WARNINGS 1


占位符

%c//字符%d//整型(有符号) - %02d打印两位整数,不够在前面补0%-2d打印两位整数,不够在后面补空格%u//整型(无符号)%ld//长整型%lld//更长的整型%s//字符串%f//单精度浮点数 - %.2f保留两位小数打印%lf//双精度浮点数 - %.2lf保留两位小数打印%p//地址%zd//size_t的值

变量的作用域和生命周期

作用域:
1. 概念: 作用域 (scope) 是程序设计概念, 通常来说, 一段程序代码中所用到的名字并不总是有效/可用的而限定这个名字的可用性的代码范围就是这个名字的作用域.
2. 局部变量的作用域是变量所在的局部范围.
3. 全局变量的作用域是整个工程.
生命周期:
1. 概念: 变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段.
2. 局部变量的生命周期是:进入作用域生命周期开始, 出作用域生命周期结束.
3. 全局变量的生命周期是:整个程序的生命周期.


跨文件全局变量使用

extern int g_val;//声明外部符号int main(){printf("%d\n",g_val);return 0;} //在同项目内全局变量跨文件使用需要声明外部符号//全局变量具有外部链接属性, 所以在其他源文件内部依然可以使用//在代码中尽量少的使用全局变量,因为全局变量在任何地方都可以使用,就变得不可控了

常量

字面常量

3;//整型字面常量3.14;//浮点数字面常量'a';//字符字面常量"xwwxw";//字符串字面常量

const修饰的常变量

int main(){const int a = 10;a = 20;//const修饰的a具有了常属性不可以直接修改int arr[a];//这样创建数组可能会报错, 因为数组创建要求[ ]中是一个常量return 0;} //const修饰的变量, 本质上还是变量

#define定义的标识符常量

#define SIZE 10int main(){int a = SIZE;int arr[SIZE] = {0};return 0;}

枚举常量

#include enum SEX{//列出了枚举常量enum SEX的可能取值MALE,FEMALE,SECRET=6};int main(){enum SEX s = SECRET;printf("%d\n",MALE);return 0;}

字符串/转义字符/注释

字符串

#include #include int main(){"x2xcrcr";//字符串以双引号引起'a';//字符以单引号引起char a = 'a';//存储字符char ch1[] = {'1','2','3','a','s'};char ch2[] = "verbwetw";printf("%s\n",ch1);printf("%s\n",ch2);printf("%d\n",strlen(ch1));printf("%d\n",strlen(ch2));return 0;}//以双引号引起就有字符串的结束标志\0//求字符串长度时\0不统计在内//%%会被printf函数解析成%

转义字符表


ASCII码表


注释

//C++的注释风格/*C语言的注释风格*/

分支和循环

if…else语句

#include int main(){int a = 0;printf("认真学习吗" />);scanf("%d",&a);if(a){printf("好offer\n");}else if(a==0){printf("烤地瓜\n");}else{printf("输入不合法\n");}return 0;}//如果好好学习 a=1 好offer//如果不好好学习 a=0 烤地瓜//如果输入其他数值 a=%d 输入不合法

while语句

#include int main(){int a = 0;scanf("%d",&a);while(a){printf("%d\n",a);}return 0;}//while后条件为真, 重复执行while语句代码块直到条件为假//while后条件为假, 不执行while语句代码块

多组输入

#include //写一个代码实现多组判断, iq大于等于140输出Geniusint main(){int iq = 0;while(scanf("%d",&iq)!=EOF)//实现多组输入{if(iq >= 140)//如果iq大于等于140输出Genius{printf("Genius\n");}}return 0; }//scanf函数返回的是读取到的数据的个数//如果scanf函数读取失败则会返回EOF//#define EOF (-1)//EOF - end of file 文件结束标志//在一些函数读取失败的时候返回EOF//VS编译器上面按 ctrl+z 会读取失败

函数

函数作用

函数是一段可重用的代码, 用于执行特定任务. 函数可以使代码更易于维护和阅读, 因为它们可以使代码更短, 更易于理解, 函数还可以使代码更易于重用, 因为它们可以在多个地方使用.


函数样例

#includeint ADD(int x,int y)//函数 - 封装代码逻辑(简化代码, 完成代码复用){//这里参数是形式参数return x+y;}int main(){int a = 0;int b = 0;scanf("%d%d",&a,&b);//相当于写成int c = a + b;int c = ADD(a,b);//这里参数是实际参数printf("%d\n",c);return 0;}

输入带空格的字符串

#include int main(){char arr[100] = {'0'};scanf("%[^\n]s",arr);//读取字符串直到读到'\n'printf("%s\n",arr);gets(arr);//读取一个带空格的字符串,存入arrprintf("%s\n",arr);fgets(arr, 100, stdin);//读取一个字符串,存入arr,最大长度为100,从stdin(标准输入输出:键盘)读取printf("%s\n",arr);//字符串打印还可以写成printf(arr); - 这里传递的是指针return 0;} //内置函数scanf,gets,fgets扩展

数组

什么是数组

1. 定义: 一组相同类型元素的集合2. 下标: 数组的每个元素都有一个下标, 下标是从零开始的3. 访问: 数组是可以通过下标来访问的

数组的创建和访问

#include int main(){int arr[10] = {0,1,2,3,4,5,6,7,8,9};//数组的创建和初始化//数组如果初始化可以不指定大小, 会根据初始化内容确定数组大小//C99标准支持变长数组int n = 10;int arr[n];//变长数组的创建不支持初始化int i = 0;while(i < 10)//数组的访问{printf("%d ",arr[i]);i++;}return 0;} 

操作符

算数操作符

+-*/%1. 除了 % 操作符之外, 其他的几个操作符可以作用于整数和浮点数.2. 对于 / 操作符如果两个操作数都为整数, 执行整数除法. 而只要有浮点数执行的就是浮点数除法.3. 对于 % 操作符的两个操作数必须为整数, 返回的是整除之后的余数.4. 除数不能为零, 除数为零编译器会报错.

移位操作符

#include int main(){int a = 15;//00000000000000000000000000001111 - 原反补//根据数值直接写出的二进制序列叫做原码//正整数的原反补码相同//int - 4byte - 32bitint b = -15;//10000000000000000000000000001111 - 原//11111111111111111111111111110000 - 反(符号位不变其它位按位取反)//11111111111111111111111111110001 - 补(反码加一)//>> - 右移a = 15;//正//00000000000000000000000000001111 - 原反补b = a >> 1;printf("%d\n",a);//15 - a是不会发生变化的printf("%d\n",b);//7//算数右移(右边丢弃,左边补原符号位)//逻辑右移(右边丢弃,左边直接补0)//00000000000000000000000000000111 - 补反原 - 7//一般编译器上采用的是算数右移(C语言没有明确规定)//正数的右移可以理解为有除二的效果a = -15;//负//10000000000000000000000000001111 - 原//11111111111111111111111111110000 - 反//11111111111111111111111111110001 - 补b = a >> 1;printf("%d\n",a);//-15printf("%d\n",b);//-8//VS编译器使用的是算数右移//11111111111111111111111111111000 - 补//11111111111111111111111111110111 - 反//10000000000000000000000000001000 - 原 - -8//<< - 左移a = 6;//00000000000000000000000000000110 - 原反补b = a << 1;printf("%d\n",a);//6printf("%d\n",b);//12//左移(左边丢弃,右边补0)//00000000000000000000000000001100 - 补反原 - 12return 0;}//移位操作符的操作数只能是整数//移位操作符移动的是补码的二进制位//打印出来的是原码的二进制位转十进制得到的数字//整数二进制位有三种表示形式: 原反补//整数在内存中存储的是补码,计算的时候也是使用补码进行计算的//a >> -2 标准未定义行为(有些编译器会报错) - 建议以后不要写这样子的(不要移动负数位)

位操作符

#include int main(){//& - 按位与int a = 3;//00000000000000000000000000000011 - 原反补int b = -5;//10000000000000000000000000000101 - 原//11111111111111111111111111111010 - 反//11111111111111111111111111111011 - 补int c = a & b;printf("%d\n",c);//3//按位与 - 有0为0,无0为1//00000000000000000000000000000011 - 补反原 - 3//| - 按位或a = 3;//00000000000000000000000000000011 - 原反补b = -5;//10000000000000000000000000000101 - 原//11111111111111111111111111111010 - 反//11111111111111111111111111111011 - 补c = a | b;printf("%d\n",c);//-5//按位或 - 有1为1,无1为0//11111111111111111111111111111011 - 补//11111111111111111111111111111010 - 反//10000000000000000000000000000101 - 原 - -5//^ - 按位异或a = 3;//00000000000000000000000000000011 - 原反补b = -5;//10000000000000000000000000000101 - 原//11111111111111111111111111111010 - 反//11111111111111111111111111111011 - 补c = a ^ b;printf("%d\n",c);//-8//按位异或 - 相同为0,相异为1//11111111111111111111111111111000 - 补//11111111111111111111111111110111 - 反//10000000000000000000000000001000 - 原 - -8return 0;}//位操作符操作的是补码的二进制位//两个相同的数异或,得到的结果是零,任何数字异或零都得到它自己,异或操作是支持交换律的

赋值操作符

#include int main(){//=int a = 12;int b = 34;b = a;a = b = 23;//连续赋值//+= -= *= /= %= &= |= ^= >>= <<= a += 1;//复合赋值(相当于a = a + 1)}

单目操作符

#include int main(){//! - 逻辑反int falg = 0;printf("%d\n", (!falg));//1//- + - 负号和正号//& * - 取地址和解引用//sizeof - 计算大小(单位是字节)printf("%d\n",sizeof falg);//4 计算变量大小时可以省略括号 - 它是操作符不是函数int arr[10];printf("%d\n",sizeof(int [10]));//40 计算arr数组类型的大小//~ - 按位取反 - 对补码的二进制位操作int z = 0;//00000000000000000000000000000000 - 原反补printf("%d\n",~z);//-1//11111111111111111111111111111111 - 补//11111111111111111111111111111110 - 反//10000000000000000000000000000001 - 原 - -1//后置++int a = 0;int b = 0;b = a++;//先使用再加加printf("%d %d\n",a,b);//前置++a = 0;b =0;b = a++;//先加加再使用printf("%d %d\n",a,b);//(类型)double a1 = 3.134;int b1 = 0;b1 = (int)a1;//强制类型转换return 0;}//单目操作符只有一个操作数//sizeof 不是函数,是一个操作符(计算大小,单位是字节)

关系操作符

==!=<==> 1. 注意:'==' 和 '=' 的书写避免出错2. 在表达式内先计算再比较3. 比较字符串, 不可以用关系操作符

逻辑操作符

&&|| 1. && 逻辑与 (并且) 2. || 逻辑或 (或者) 3. 采用短路求值4. 计算结果是真使用1表示, 计算结果是假使用0表示

条件操作符

exp1 ? exp2 : exp3 1. 条件操作符也叫三目操作符2. 真计算不计算假 不计算 计算

逗号表达式

exp1, exp2, exp3 1. 从左向右依次计算2. 表达式的结果是最后一个表达式的计算结果

下标引用, 函数调用和结构体成员访问操作符

[]().->1. 下标引用操作符是用于访问数组内的元素的: 数组名[下标]2. 函数调用操作符是用于进行函数的使用的: 函数名(参数)3. 函数的参数是可变的.像 printf, scanf ... 具有可变参数列表的库函数, 它们的参数个数是不确定的4. 结构体成员访问操作符是用于结构体访问的: 结构体变量.成员名 结构体指针->成员名

表达式求值

表达式求值的要素

1. 表达式求值的顺序一般是由操作符的优先级和结合性决定.2. 有些表达式的操作数在求值的过程中可能需要转换为其他类型.

隐式类型转换 (整型提升)

1. C语言的整型算术运算总是至少以缺省整型类型的精度来进行的. 为了获得这个精度, 表达式中的字符和短整型操作数在使用之前被转换为普通整型, 这种转换称为整型提升.2. 表达式的整型运算要在CPU的相应运算器件内执行, CPU内整型运算器的操作数的字节长度一般就是 int 的字节长度, 同时也是CPU的通用寄存器的长度. 所以, 即使是两个 char 类型的相加, 在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度.3. 通用CPu是难以直接实现两个八比特字节直接相加运算的 (虽然机器指令中可能有这种字节相加指令) . 因此, 表达式中各种长度可能小于 int 长度的整型值, 都必须先转换为 int 或 unsigned int, 然后才能送入CPU去执行运算.

整型提升是怎么进行的

#include int main(){char c1 = 5;//00000000000000000000000000000101 - 原反补(整型的实际长度)//00000101 - c1里面真实存放的长度(二进制的补码发生了截断)char c2 = 127;//01111111 - c2里面真实存放的长度char c3 = c1 + c2;//计算时要进行整型提升//c1提升: 00000000000000000000000000000101 - 补(补码整型提升还是补码)//c2提升: 00000000000000000000000001111111//相加: 00000000000000000000000010000100//c3存放: 10000100printf("%d\n", c3);//-124//%d - 十进制的形式打印有符号的整数//打印时发生整型提升 - 打印的是原码//11111111111111111111111110000100 - 补//11111111111111111111111110000011 - 反//10000000000000000000000001111100 - 原 - -124char a = 0xb6;short b = 0xb600;int c = 0xb6000000;if(a==0xb6)printf("a");if(b==0xb600)printf("b");if(c==0xb6000000)printf("c");//只打印cchar z = 1;printf("%u\n",sizeof(z));//1printf("%u\n",sizeof(+z));//4 - 发生了整型提升//%u - 十进制的形式打印无符号的整数return 0;}//整形提升是按照变量的数据类型的符号位来提升的//有符号的类型整型提升,补原符号位(最高位就是符号位)//无符号的类型整型提升,补0(每一位都是有效位)//整型提升只适用于比int小的类型//表达式运算时不关心有无符号 (只使用补码运算), 使用时才关心有无符号

算数转换

1. 如果某个操作符的各个操作数属于不同的类型, 那么除非其中一个操作数的转换为另一个操作数的类型, 否则操作就无法进行. 下面的层次体系称为寻常算术转换.long double doublefloat unsigned long int long intunsigned intint2. 如果某个操作数的类型在上面这个列表中排名较低, 那么首先要转换为另外一个操作数的类型后执行运算.3. 警告: 算术转换要合理, 要不然会有一些潜在的问题.

表达式求值顺序的影响因素

1. 操作符的优先级2. 操作符的结合性3. 是否控制求值顺序4. 可以加上括号控制求值顺序5. 两个相邻的操作符的执行顺序, 取决于他们的优先级. 如果两者的优先级相同, 取决于他们的结合性.6. 通过以上规则, 对于一些无法确定唯一的计算路径的问题表达式, 在不同的编译器上结果可能不同.7. 我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径, 那这个表达式就是存在问题的.

操作符的优先级和结合性表 (由高到低)


关键字

typedef

typedef unsigned int u_int;//将无符号的整型重命名为u_int//创建一个名为 dstruct Node 的结构体类型//并将 dstruct Node 重命名为 Nodetypedef struct Node{int data;struct Node* next;}Node;int main(){u_int num1 = 0;unsigned int num2 = 0;//num1 和 num2 创建的效果相同return 0;}

static

#include extern int g_val;//声明一下另一个.C文件中定义的g_val全局变量extern int ADD(int , int);//声明一下另一个.C文件中定义的ADD函数void test(){static int a = 5;//使a在程序彻底结束之后才销毁//static修饰的变量就是静态变量a++;printf("%d ",a);}int main(){int i = 0;while(i<10){test();i++;}printf("%d\n",g_val);//如果g_val在另一个.C文件中是static修饰的, 这里使用会报错printf("%d\n",ADD(1,2));//如果ADD在另一个.C文件中是static修饰的, 这里使用会报错return 0;}//static 修饰局部变量//static 修饰局部变量改变了变量的存储类型(位置由栈区变为静态区)//由此使得这个静态变量的生命周期变长了, 直到程序结束才结束//它的作用域仍是该局部变量所在的局部范围//static 修饰全局变量//static 修饰全局变量, 使得全局变量的外部链接属性消失//使得该全局变量只具有内部链接属性//这个静态变量只能在自己所在的源文件内部使用, 不能在其他源文件内部使用了//感觉像是作用域变小了, 但是不影响其存储位置//static 修饰函数//static 修饰函数和其修饰全局变量是一样的//一个解决方案可以创建多个项目, 一个项目可以创建多个文件

register

int main(){register int num = 10;//建议将该数据存储入寄存器//register 仅仅是建议的作用//到底是不是真的放在寄存器中, 取决于编译器的判断//其实不用register关键字, 该把变量放到寄存器的时候编译器会自动放进去return 0;}

const

#include void test1(){int n = 10;int m = 20;int *p = &n;*p = 20;//可以p = &m;//可以}void test2(){int n = 10;int m = 20;const int* p = &n;//*p = 20; - 不行p = &m;//可以}void test3(){int n = 10;int m = 20;int *const p = &n;*p = 20;//可以//p = &m; - 不行}int main(){//测试无cosnt的test1();//测试const放在*的左边test2();//测试const放在*的右边test3();return 0;}//const如果放在*的左边//修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可变//const如果放在*的右边//修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变//const还可以同时放在左右两边

宏和指针

#define定义的宏

#include #define ADD(x,y) ((x)+(y))//宏// 宏名 参数宏的实现体int main(){int a =10;int b = 20;int c = ADD(a,b);printf("%d\n",c);return 0;}//#define 和#include 都是预处理指令

内存

1. 内存是电脑上特别重要的存储器, 计算机中程序的运行都是在内存中进行的.2. 为了有效的使用内存, 就把内存划分成一个个小的内存单元, 每个内存单元的大小是1个字节.3. 为了能够有效的访问到内存的每个单元, 就给内存单元进行了编号, 这些编号被称为该内存单元的地址. 4. 在计算机上有地址线 (物理的电线) , 输出的高低电平信号转换成数字信号就形成了地址.5. 变量是创建内存中的 (在内存中分配空间的) , 每个内存单元都有地址, 所以变量也是有地址的.6. C语言中地址也叫做指针 (编号 == 地址 == 指针)

指针变量的创建和使用

#include int main(){int a = 15;int* pa = &a;//指针变量的创建//&a 取出的是第一个字节地址//存放指针的变量叫指针变量//int*int表示pa指向的是int类型的变量//int**表示pa是指针变量printf("%p\n",pa);//打印出的地址是十六进制的*pa = 30;//将该地址对应的值改成30printf("%d\n",a);return 0;}//十进制: 15//二进制: 00000000 00000000 00000000 00001111//十六进制: f//计算机表现出来的十六进制是: 0x00 00 00 0f//指针 - 编号 - 地址//指针变量 - 存放指针的变量 - 变量//一般口头语上说的指针就是指针变量//变量对应的地址一旦确定就无法改变

指针变量的大小

#include int main(){int a =10;int* p = &a;printf("%zd\n",sizeof(p));printf("%zd\n",sizeof(*int));//8/4return 0;} //32位机器上://地址是32个二进制位, 这个地址要存储的话要四个字节, 所以在32位机器上, 指针变量的大小是四个字节//64位机器上://地址是64个二进制位, 这个地址要存储的话要八个字节, 所以在64位机器上, 指针变量的大小是八个字节

结构体

结构体的创建和使用

#include //学生struct Stu{//学生的相关属性char name[20];//一个汉字是两个字符int age;char sex[5];};//结构体的创建int main(){struct Stu s = {"张三", 20, "男"};//结构体的初始化printf("%s %d %s\n",s.name,s.age,s.sex);//结构体成员访问return 0;}//结构体是自定义的复杂类型

结构体的成员访问

#include struct Book{char name[50];char author[20];float price;};//第一种访问方式void print1(struct Book a){printf("%s %s %f",a.name,a.author,a.price);}//第二种访问方式void print2(struct Book* a){printf("%s %s %f",(*a).name,(*a).author,(*a).price);printf("%s %s %f",a->name,a->author,a->price);}int main(){struct Book a = {"《鹏哥C语言》","鹏哥",66.6f};print1(a);print2(a);return 0;}