一.c语言概述1.main函数在程序里的位置可以随意但在程序中有且仅有一个main函数也总是从main函数开始main函数可以调用其他函数但其他函数不可以调用main函数2.单行注释 //这是一个单行注释多行注释/*这是一个多行注释*/3.变量都要先定义后使用double x,double y; 定义多个同类型变量时只需在开头写一次类型正确写法应为double x, y;C 语言允许使用空类型void比如用于函数返回值或指针类型枚举类型enum属于基本数据类型数组属于构造类型由基本类型组合而成4.字符和字符串字符常量用单引号 包裹里面只能放1 个字符包括转义字符。比如a、 空格字符合法、\n换行符合法。字符串常量用双引号 包裹里面可以放 0 个、1 个或多个字符系统会自动在末尾加\0作为结束标志。比如空字符串合法、 空格字符串合法、abc合法。也就是说如果是表示单个空格字符应该用单引号如果是表示空格字符串用双引号二者类型不同不能混用5.宏定义#define 宏名 文本处理之后在运行的时候会用文本替换宏名没有结尾否则替换的时候会把一起替换然后就会有错误#define 可以出现在程序的任意位置6.C 语言中类型转换的语法是 (float)(y/n)而不是 float(y/n)语法错误。7.scanf的格式控制符中不能使用.2这种精度限定这种写法是错误的scanf(%6f, x); %6f表示输入的浮点数总宽度为 6 位包括整数部分、小数点和小数部分输入36.582时它的总宽度为 53、6、.、5、8、2 是 6 位符合要求且scanf会完整读取该数值并赋值给x。8.%c是字符格式符对应char类型变量s%d是整数格式符虽然char本质是整数类型但这种写法不符合输入字符的语义不过在语法上是允许的会把输入的 ASCII 码值存入s%u是无符号整数格式符和%d类似语法上允许只是会把输入的无符号整数存入s。9.构成c源程序的基本单位是函数而不是语句语句结束的符号是分号例子1宏替换#define r 2#define rr r2#define rrr rr*2预处理替换 rrr/3先替换 rrr 为 rr*2 再替换 rr 为 r2注意是直接替换并不是整体替换得到 r2*2 再替换 r 为 2得到 22*2二.基本数据类型与运算1.字符型数据以ASCII码值存储其余以补码存储2.标识符不能有空格不能以数字开头3.按位与均为1才是1按位或:有一个是1才是1按位异或二进制位不相等结果为14.优先级 算术关系||条件:赋值逗号记忆口诀 非 增 算 关 与 或5.幂函数expx以e为底参数为其指数值powxy计算x的y次方即x^y绝对值absfabslabs求整数浮点数和长整型数的绝对值锐角计算atanA/Barctan阿法不过这个算出来的是弧度制的角度如果是角度值还需要*180/3.1415926开根号sqrt6.m是字符串常量M也是字符串常量字符串不能直接用进行运算所以这个表达式不合法。(ab)是一个表达式其结果是一个临时值而运算符只能作用于变量不能作用于表达式或常量所以(ab)不合法。强制类型转换运算符如(int)的优先级高于算术运算符、-、*、/例如(int)3.5 2会先执行强制转换再执行加法。7.浮点数常量科学计数法的格式为尾数E指数 或 尾e指数其中指数部分必须是整数可以是正整数或负整数5.68是普通的小数形式浮点常量合法。3.1E2.5指数部分是2.5不是整数非法。-3.0E-1指数部分是-1整数合法。1.0e2指数部分是2整数合法。E-7不合法科学计数法的浮点数必须有数字部分正确形式应为1E-7或0E-7。1.2E-2.1不合法科学计数法的指数部分(-2.1)必须是整数不能是小数。55*868不合法他不是一个常量而是一个运算表达式8.整数 / 整数 整数 → 输出用 % d整数 / 小数 或 小数 / 整数 小数 → 输出用 % fy7%31结果y1不为 2y7/32结果y2不符合要求9.sizeof是用来计算数据类型 / 变量所占内存字节数的运算符。当sizeof的操作数是类型比如int、float时必须加括号sizeof(int)。当sizeof的操作数是表达式时可以省略括号而且这个表达式不会真正执行只会根据表达式的结果类型来计算字节数。例如表达式不参与运算int a 5;printf(%zu\n, sizeof(a 3.14)); // 可以省略括号写成sizeof a 3.14也可以但注意优先级printf(a的值%d\n, a);a 3.14这个表达式的结果类型是doubleint会隐式转换为double所以sizeof(a 3.14)等价于sizeof(double)在大多数系统中结果是8。关键a的值不会被修改a 3.14这个运算不会真正执行只是推导类型再比如带副作用的表达式int b 10;printf(%zu\n, sizeof(b));printf(b的值%d\n, b);b表达式的类型是int所以sizeof(b)结果是432 位系统int占 4 字节。关键b不会执行b的值仍然是10不会变成11。再再比如int c 2;// 正确写法sizeof (c 3) 或者 sizeof c 3注意优先级printf(%zu\n, sizeof c 3); // 等价于 (sizeof c) 3因为sizeof优先级高于printf(%zu\n, sizeof(c 3));所以sizeof c结果是44 3 7sizeof(c 3)结果是4c3类型还是int。10.bw i / 100;sw (i / 10) % 10; // 这里的十位不是直接i/10这是大坑gw i % 10;例子1到底谁是1\0 - 0\0 的 ASCII 码是00 的 ASCII 码是48计算得0 - 48 -48结果不是 1。1 - 01 的 ASCII 码是49计算得49 - 0 49结果不是 1。C1 - \0\0 的 ASCII 码是0计算得1 - 0 1结果为 1 。D1 - 00 的 ASCII 码是48计算得1 - 48 -47结果不是 1。例子2:三目运算符的求值m a b ? (a, b--, b%a) : (a--, b, b/a)先确定表达式1谁真假-------真就执行表达式2--------假就执行表达式3这里表达式1为假执行表达式33里面又嵌套了逗号表达式先a--再b最后执行b/a--的值做整个表达式的值例子3运算谁合法a4b;赋值运算符的左侧必须是变量不能是表达式a4所以不合法。ca/2b;a/2是表达式不能出现在赋值运算符的左侧所以不合法。a*b1;这是复合赋值运算符等价于a a * (b 1);语法合法。ab/3;运算符的使用不合法b/3是表达式不能进行自增操作所以不合法。三.结构化程序设计1.for和while的continuewhile循环中continue会直接跳回条件判断可能跳过循环变量更新导致死循环for循环中continue会先执行循环变量的更新表达式 3再跳回条件判断不会跳过变量更新。也就是说while 的 continue 直接回条件for 的 continue 先更新变量再回条件。2.if-else语句的语法结构根据C语言规则else必须紧接在if语句之后不能有其他语句插入。例如在给定代码中if (a 1)的主体是b 1;而c 2;是独立语句。else试图与if配对但因if已结束导致语法错误。编译时会提示else无对应if程序无法通过编译。四 .数组1.数组元素的引用是通过下标进行的其下标必须是整型常量或整型表达式二维数组在内存中的存储方式是按行存放例子1初始化int x[1][2]{{11}, {33}};int x[1][2] 确实是 1行2列总共能放2个整数。初始化式是{{11}, {33}}注意外面的大括号里用逗号隔开了两组{}。在C语言中最外层的每一组{}代表一行。既然你定义只有 1行初始化时却给了2行的数据第一行放11第二行放33当然报错int z[3][2]{{11,22}, {34}};int z[3][2] 定义的是 3行2列总共能放 6个 整数。初始化式是 {{11, 22}, {33, 44}}这里只给了 2行 的数据第一行11,22第二行33,44。定义了3行只给了2行C语言规定剩下的那一行第三行会自动补 0变成 {0, 0}。数据总数4个没有超过总容量6个分组也没超出总行数2行 ≤ 3行所以语法完全正确。五.函数1.在 C 语言中函数返回值的类型是由定义函数时所指定的函数类型决定的在C语言中如果函数定义时没有指定返回值类型则默认返回类型为 int而不是由return语句中的表达式类型、主调函数类型或形参数据类型决定。如果return语句的表达式类型和函数定义的类型不一致系统会自动将表达式的值转换为函数定义时指定的类型。2.static int y1; 里的初始化y1只会执行一次是在程序第一次调用这个函数的时候完成的之后再调用函数时不会再执行y1这个赋值操作而是直接使用y上一次调用结束后保留的值。也就是说变量的存储空间在程序运行期间一直存在不会像普通局部变量那样函数结束就销毁。变量的初始化操作只会执行一次后续调用函数时会保留上一次修改后的值。六.指针例子1解引用和取地址1.int a0, b, *pb, *qa如何让写和ba等价*p a; 错误因为*p是inta是int*类型不匹配。p *q; 错误p是int* *q是int类型不匹配。*p *q; 正确因为p是bq是a等价于ba。*p是找到p指向的变量b*q是找到q指向的变量a---读出a的值p q; 让p指向a不影响b的值所以不等价。相当于改变p指向的对象2.int *p1a, *p2b; 定义了两个指针变量p1 指向 ap2 指向 b什么与ab等价p1p2 是两个指针的地址相加不是值的和错误。p1p2 是两个指针变量自身的地址相加不是值的和错误。*p1 是取 p1 指向的变量 a 的值*p2 是取 p2 指向的变量 b 的值*p1*p2 就是 ab正确。*a 和 *b 写法错误a 和 b 不是指针不能直接用解引用操作符错误。例子2char str[] Deepseek V3怎么找到字符 s*p 4和*p 4*p 是D执行D 4后*p的值变成D 4即 ASCII 值为 68472对应字符H不是s。 *p 是D*p 4 是D 4即H不是s。*(p 4)p 4 表示指向str[4]的地址*(p 4) 就是取该地址的内容即s符合要求。p 4这是一个地址值指向str[4]的指针不是字符s。例子3赋值int x 0, *p;这里 x 是整型变量p 是整型指针变量存储内存地址且 p 未初始化是野指针。A. *p x;*p 表示指针 p 指向的内存单元。但 p 此时是野指针没有指向合法的内存地址直接赋值会导致未定义行为程序崩溃、数据错乱等语法上虽能编译但逻辑错误。B. *p NULL;NULL 是地址常量通常是 (void*)0而 *p 是 int 类型。把地址值赋给整型变量类型不匹配同时 p 仍是野指针同样会导致未定义行为。C. p x;p 是指针类型存储地址x 是 int 类型存储数值。直接将整型值赋给指针属于类型不匹配编译会报错或警告逻辑上也错误因为 0 不是合法的内存地址。D. p NULL;NULL 是 C 语言中专门表示 “空地址” 的常量类型与指针兼容。将 p 赋值为 NULL表示指针不指向任何有效的内存空间是安全且规范的初始化方式避免野指针问题。七.结构体和共用体例子11.1.scanf(%s, (std.name));std是结构体数组名std.name的写法本身就是错误的因为数组名不能直接用.name访问成员必须指定数组元素如std[0].name。而且name是字符数组数组名本身就是地址不需要再用取地址这里存在双重错误。1.2.scanf(%c, (std[2].sex));std[2]是结构体数组的第 3 个元素.sex是字符成员用取地址后传入scanf写法正确。1.3.scanf(%c, (p-sex));p是指向std[0]的指针p-sex是访问结构体成员用取地址后传入scanf写法正确。1.4.scanf(%d, ((*p).age));*p等价于std[0](*p).age是访问结构体成员用取地址后传入scanf写法正确。