Author:onceday date:2022年7月19日
C语言是1972年由美国的Dennis Ritchie设计发明的,并首次在UNIX操作系统的 DEC PDP-11 计算机上使用。它由早期的编程语言BCPL (Basic Combind Programming Language)发展演变而来。
C语言有多个版本,最早的统一版本是ANSI(美国国家标准研究所)标准。之后有C99,C11,C17,…等。
一个c语言源程序可以由一个或多个源文件组成,每个源文件都有一个且只能有一个main函数,即主函数。但所有源文件中只能有一个主函数。
该主函数名字无需是main,任意合适名字即可,只要c初始化函数_init)里面名字对应就行。
整数型,字符型,浮点型,枚举类型。
字符型、整数型大小和取值范围
| 数据类型 | 数据长度(32位GNU编译器) | 数据长度(64位GNU编译器) |
|---|---|---|
| char | 8bit | 8bit |
| unsigned char | 8bit | 8bit |
| short | 16bit | 16bit |
| unsigned short | 16bit | 16bit |
| int | 32bit | 32bit |
| unsigned int | 32bit | 32bit |
| long | 32bit | 64bit |
| unsigned long | 32bit | 64bit |
| long long | 64bit | 64bit |
| unsigned long long | 64bit | 64bit |
| 指针 | 32bit | 64bit |
C标准规定了各种整数类型的最小位长度,因此有:
char = unsigned char <= short = unsigned short <= int = unsigned int <=
long = unsigned long <= long long =unsigned long long
浮点数大小和取值:
(xxxxxxxxxxxx需要取证xxxxxxxxxxx)
| 数据类型 | 长度(32位gnu编译器) | 有效数字 | 取值范围 |
|---|---|---|---|
| float | 32bit | 6-7 | 3.4*10(-38)`? |
| double | 64bit | ||
| long double | 96bit |
数组类型,结构体类型,共用体类型
变量名由数字、字母、下划线组成,首字符必须为字母,下划线起分割作用,不作为变量名的第一个或最后一个字符。
自动型是从低向高转换,同等情况下,由有符号向无符号转换。
在表达式中,类型会自动向最高型转换,最后再损失精度型转换回去。
printf/scanf类函数。
| 转换字符 | 变元类型:输出形式 |
|---|---|
| d,i | int:十进制数 |
| o | int:无符号八进制数 |
| x,X | int:无符号十六进制数 |
| u | int:无符号十进制数 |
| c | int:单个字符 |
| s | char*:顺序打印直到遇到’\0’或由精度指定的字符数为止。 |
| f | double:十进制小数表示。缺省为6. |
| e,E | double: 指数形。精度缺省为6 |
| g,G | double:如果指数小于-4或者大于等于精度,则用%e/%E输出,否则用%f格式输出,尾部的0和小数点不打印。 |
| p | void* 类型:指针 |
| % | 打印一个百分号 |
| - | 指定被转换的变量按照左对齐的形式输出,默认右对齐。 |
| 数字(.) | 指定最小的字段宽度,其他位置将被填充。 |
| . | 将字段宽和精度分开 |
| (.)数字 | 表示精度,指定一个字符串所要打印的最大字符数,浮点数小数位数,整数最小数字位数。 |
| h ,l | short类型和long类型 |
| + | 在一个带符号数前加"+"或“'-'号 |
| 0 | 数值右对齐时,用0填充多余的字符位置 |
| 空格 | 只用于转换有符号值,当值非负时,把一个空格添加到它的开始位置。 |
以下是几种常见的常量表示方法:
| 数据类型 | 表示 |
|---|---|
| int | 123 |
| unsigned int | 123u |
| long | 123L |
| unsigned long | 123UL |
| float | 123.0f |
| double | 123.0 |
| long double | 123.0L |
| char | ‘a’ |
| char* | “ab” |
#define 符号 常量
const 类型 符号 = 表达式;
关于宏的文档可参阅:https://blog.csdn.net/Once_day/article/details/124635280
枚举常量,未赋予初值的,将根据前一个值递增,第一个如果未赋值,则默认为0。
enum Number {one = 1,three= 3}
| 转义字符 | 说明 |
|---|---|
\' | 单引号 |
\" | 双引号 |
\\ | 反斜杠 |
\0 | 空字符 |
\000 | 八进制 |
\a | 蜂鸣 |
\b | 退格符 |
\f | 换页符 |
\n | 换行符 |
\r | 回车符 |
\t | 水平制表符 |
\v | 垂直制表符 |
\xhh | 十六进制符 |
如下两种,具体看参考博文:https://blog.csdn.net/Once_day/article/details/124635280c
#define debug(format,arg...) printf(format,args)
#define debug(format,...) printf(format,##__VA_ARGS__)
后一个是特别优化的宏,可消除零参数时的问题。但不同编译器支持的格式不一样,需要特别注意。
+ - * / % ++ --
整数除法运算结果取整
%运算不能作用于浮点型对象
由负的运算分量时,整数除法截取的方向、上溢和下溢需根据具体机器情况决定。
> < >= <= == !=
&& || !
& | ~ ^ << >>
这些运算符只能作用于整型分量
<< 和 >> 运算分量的值必须是正的
= += -= *= /= %= &= |= ^= >>= <<=
xx ? xx:xx;
xxx,xxx;
int x = (3,4); // x =4
由逗号分隔的各个表达式从左到右的进行求值,结果和类型是最右的表达式。
类型转换符 () [] -> . * &
| 优先级 | 运算符 | 结合性 |
|---|---|---|
| 1 | () [] -> . | L-R |
| 2 | ! ~ ++ – +(一元) -(一元) * & (type) | R-L |
| 3 | * / % | L-R |
| 4 | + - | L-R |
| 5 | << >> | L-R |
| 6 | < <= > >= | L-R |
| 7 | == != | L-R |
| 8 | & | L-R |
| 9 | ^ | L-R |
| 10 | ||
| 11 | && | L-R |
| 12 | | | |
| 13 | ?: | R-L |
| 14 | = += -= *= /= %= &= ^= |= <<= >>= | R-L |
| 15 | , | L-R |
表达式 ;
函数名称(参数......);
内置语句;
控制语有三类:
条件判断:if,switch
循环执行:while,do while ,for
转向语句:break,goto,continue,return
如:
for(i=1;i<=100;i++){....}
break可跳出最内层的switch或循环语句。
continue语句的作用是跳过本次循环中剩余的语句而强行执行下一次循环。
continue语句只能用在for、while、do-while等循环体中。
返回类型 函数名(参数....)
{
说明序列与语句序列
}
函数不允许嵌套定义!
形参与实参:
函数的参数分为形参和实参两种。
形参出现在函数定义中,在整个函数体内都可以使用,离开该函数后无效。
实参出现在主调函数中,进入被调函数后,实参变量也不能使用。
发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
函数的形参和实参具有以下特点:
形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。
实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。
函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
return用于返回值,其值应函数定义中返回值的类型应保持一致。如果两者不同,则以函数定义为准,自动进行类型转换。
return ;//什么都不返回
函数调用:函数名(实际参数表)
递归调用: 一个函数可以直接或间接调用它自已称为递归调用。这种函数称为递归函数。
全局变量:作用域是定义处至全文件结尾,在定义前使用,需要先声明。
局部变量:作用限于大括号内部。在局部位置上优先级高于外部变量。
静态变量:作用域限于本文件,存储在全局存储区。
寄存器变量:
1)用关键字register声明的变量叫“寄存器变量”。寄存器变量放在机器的寄存器中,这样可以使程序更小,执行速度更快。
2)只有自动变量和函数形参可以定义为寄存器变量。
3)不能访问寄存器变量的地址。
4)程序中寄存器变量的个数超过机器限制时,编译器将之忽略掉。
一维数组:
//类型说明符 数组名 [常量表达式]
初始化:
int latitude[] = {0, 1, 2, 3, 4};
引用元素:
latitude[2];
获取首地址:
latitude;
&latitude[0];
在C语言中,二维数组是按行排列的。即放完一行之后顺次放入第二行。
int a[3][4];
赋值初始化:
int array[5][3]={{80,75,92},{61,65,71},{59,63,70},{85,87,90},{76,77,85} };
int array[5][3]={ 80,75,92,61,65,71,59,63,70,85,87,90,76,77,85};
int array[][3]={ 80,75,92,61,65,71,59,63,70,85,87,90,76,77,85};
int array[5][3]={{80},{61},{59},{85},{76}}; //只对部分元素赋初
array[1][1] = 65;
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
Array: [index] = value
int a[6] = { [4] = 29, [2] = 15 };
等价为int a[6] = { 0, 0, 15, 0, 29, 0 };
[first … last] = value.
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
类型说明符 *变量名;
取地址运算符&只能应用于内存中的对象(即变量与数组元素),它不能对表达式、常量或寄存器变量进行操作。
指向数组的指针:
类型说明符 (*指针名)[数组长度] ;
指向数组:
类型说明符 *指针名[数组长度];
函数指针:
类型说明符 (*指针变量名)(变元说明表);
返回值是指针的函数:
类型说明符 *函数名(变元说明表);
函数指针数组:
类型说明符 (*指针变量名[数组长度])(变元说明表);
指向常量的指针:
const int *a;
指针常量:
int * const a;
结构定义的一般形式:
struct 结构名{
成员列表
};
结构体指针:
struct 结构名 *结构指针变量名
结构体嵌套定义必须要先声明。
类型定义符typedef用于用户自定义类型说明符。
typedef 原类型名 新类型名
联合的所有成员引用的是内存中的相同位置。用于不同时刻保存不同类型和大小的对象的变量。
结构体位段声明:
struct registerinfo_s {
unsigned int command:5;
unsigned int error_code:8;
unsigned int write_protect:1;
unsigned int ready:1;
};
int类型位段成员是有符号还是无符号数。
位段中的成员在内存中是从左向右分配还是从右向左分配。
许多编译器把位段成员的长度限制在一个整型值的长度之内,所以一个能够运行于32位整数的机器上的位段声明可能在16位整数的机器上无法运行。
位段中的2个成员,当第1个成员剩余的位无法容纳第2个成员时,编译器可能把第2个成员放在内存的下一个字,也可能直接放在第1个成员后面。
不能对位段成员取地址。
预处理参照:https://blog.csdn.net/Once_day/article/details/124635280c
由于linux gcc编译默认只带libc,因此库函数后续再介绍。
深入c语法将以专题形式总结。