C语言基础知识梳理
-
一、变量和基本类型
printf("%f\n", 1/0.0); // 无穷大。我的电脑上为:1.#INF00 printf("%f\n", -1/0.0); // 无穷小。我的电脑上为:1.#INF00 printf("%f\n", 0.0/0.0); // 空。我的电脑上为:-1.#IND00
讯享网
讯享网int a; // a是int类型的变量 double b=1.0; //b是double类型的变量,赋1.0为初值 char c, d; // c, d是char类型的变量 2、常用特殊前缀 extern int a; // 声明一个int类型的变量a,一般用在.h文件中声明项目全局变量 const int b=1; // 定义一个不可变的变量b,使用const关键字都要赋初值 static int c=1; // 在函数中使用,只在第一次使用时初始化,相当于作用域在函数内的全局变量 typedef long long int; // 把long long当作int使用 3、数组与初始化变量 int a=1; // 给a初始化为1 // 以下为C99加入的特性 int b[10] = {1}; // 第一个元素初始化为1,其他9个元素初始化为0 int c[10] = {0}; // 全部初始化为0,常用初始化手段 int d[10] = {[1]=1, 2, [4]=4}; // 0 1 2 0 4 0 0 0 0 0 4、变量作用域 变量有两种类型:局部变量全局变量,变量作用域即变量可使用的范围。 对于局部变量可以简单理解为大括号{}内即为一个作用域,变量在哪个大括号内,作用域就在哪。 对于全局变量的作用域就是在当前的.c文件中,在.h文件声明后可以在整个项目内使用。 对于同名变量,小作用域的变量会在其作用域中覆盖大作用域的变量。 (三)字符串 字符串在c语言中有两种形式char*和char[],这里简单分辨下两者之间的不同。 char* c1="HelloWorld!"中,c1指向代码段中的常量,只读不写,且常量相同,指向的地址也相同。 char c2[]="HelloWorld!"中,c2指向堆栈段中的数据,可读可写,相当于把代码端的数据拷贝了出来。 (四) 自定类型——结构体 结构体可以看作是一种个基础类型复合的类型。 // 声明如下: struct DATE{ int year, month, day; }; // 几种定义方式如下: struct DATE date1; // 不赋初值 struct DATE date2={2020, 4, 5}; // 根据结构体中的顺序赋初值,这里是年月日 struct DATE date3 = {.year=2020, .day=5}; // 给单独变量赋初值 struct DATE *date4 = &date3; // 用指针取date3地址(指针后面会单独说) // 几种赋值方式如下: date3 = (struct DATE){.year=1999}; // 将数据强制转换成struct DATE类型赋值 date3 = date2; // 自动赋值 date3.year=2010; // 对变量中单一元素赋值 date4->year=2010; // 对指针所指变量中的单一元素赋值 // 常用声明 typedef struct DATE2{ int year, month, day; } D; D date5; // 这样就可以不用写struct DATE2这么一长串,取而代之用D来表示 扩展:union union作为关键字与struct类似,但是struct中每个成员都是单独的内存,而union只占最大成员变量的大小,通常用与二进制与十进制的转换。 union DATE{ int year; int month; int day; }; /* 一个union DATE只有一个int大小 */ 扩展:enum枚举,枚举类似#define,但是有体系些(c语言的枚举不好用) // 声明枚举, 默认下标RED:0, YELLOW:1, GREEN:2 enum COLOR1 {RED1, YELLOW1, GREEN1}; // 自定下标 enum COLOR2 {RED2=1, YELLOW2, GREEN2=5};
二、表达式
这里给出运算符优先级
优先级 运算符 名称或含义 使用形式 结合方向 说明
1 [] 数组下标 数组名[整型表达式] 左到右
() 圆括号 (表达式)/函数名(形参表)
. 成员选择(对象) 对象.成员名
-> 成员选择(指针) 对象指针->成员
2 - 负号运算符 -算术类型表达式 右到左 单目运算符
(type) 强制类型转换 (纯量数据类型)纯量表达式
++ 自增运算符 ++纯量类型可修改左值表达式 单目运算符
-- 自减运算符 --纯量类型可修改左值表达式 单目运算符
* 取值运算符 *指针类型表达式 单目运算符
& 取地址运算符 &表达式 单目运算符
! 逻辑非运算符 !纯量类型表达式 单目运算符
~ 按位取反运算符 ~整型表达式 单目运算符
sizeof 长度运算符 sizeof 表达式 / sizeof(类型)
3 / 除 表达式/表达式 左到右 双目运算符
* 乘 表达式*表达式 双目运算符
% 余数(取模) 整型表达式%整型表达式 双目运算符
4 + 加 表达式+表达式 左到右 双目运算符
- 减 表达式-表达式 双目运算符
5 << 左移 整型表达式<<整型表达式 左到右 双目运算符
>> 右移 整型表达式>>整型表达式 双目运算符
6 > 大于 表达式>表达式 左到右 双目运算符
>= 大于等于 表达式>=表达式 双目运算符
< 小于 表达式<表达式 双目运算符
<= 小于等于 表达式<=表达式 双目运算符
7 == 等于 表达式==表达式 左到右 双目运算符
!= 不等于 表达式!= 表达式 双目运算符
8 & 按位与 整型表达式&整型表达式 左到右 双目运算符
9 ^ 按位异或 整型表达式^整型表达式 左到右 双目运算符
10 | 按位或 整型表达式|整型表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到右 双目运算符
13 ?: 条件运算符 表达式1? 表达式2: 表达式3 右到左 三目运算符
14 = 赋值运算符 可修改左值表达式=表达式 右到左
/= 除后赋值 可修改左值表达式/=表达式
*= 乘后赋值 可修改左值表达式*=表达式
%= 取模后赋值 可修改左值表达式%=表达式
+= 加后赋值 可修改左值表达式+=表达式
-= 减后赋值 可修改左值表达式-=表达式
<<= 左移后赋值 可修改左值表达式<<=表达式
>>= 右移后赋值 可修改左值表达式>>=表达式
&= 按位与后赋值 可修改左值表达式&=表达式
^= 按位异或后赋值 可修改左值表达式^=表达式
|= 按位或后赋值 可修改左值表达式|=表达式
15 , 逗号运算符 表达式,表达式,… 左到右 从左向右顺序结合
总结优先度: 特殊运算符(括号、地址类) > 单目运算符 > 算数运算符(乘除>加减) > (移位运算) > 判断运算符(比较>相等) > (位运算) > 逻辑运算符(&&>||) > 三目运算符 > 赋值运算符 > 逗号运算符
针对十进制字面值
<<:左移数据,相当于乘2(右边填0)
>>:右移数据,相当于除2(unsigned左填0,signed左边填原来的最高位(因为负数移位还要是负数))
1、switch语句
switch(ch){ // switch是传入整数并判断整数进行判断 case 'a': ... break; case 'b': ... break; default: ... }
(3)switch只能传入整数进行判断,上面的例子就是将char类型的ch转换成了ASCII码
进行比较.
(1)while适用于不知道次数的循环
2、do while语句
讯享网do{ 语句 }while(条件);
1)do while适用于不知道次数且要先做一遍的循环
三、跳转语句
break;直接跳出当前条件语句或迭代语句,能且只能 跳出 当前 的 一个 语句。
continue;在 条件语句 中表示什么都不做(替代空语句);在 迭代语句 中表示 直接进入下一轮循环,不执行完当前循环 。
goto;跳转到指定位置(该位置必须有声明),例子:
start: // goto声明 ... // 语句 ... // 语句 ... // 语句 goto start; //跳转到start声明位置
!!!注意,goto仅推荐用于跳出多重循环,例如:
讯享网for (int i=0; i<n; i++) { for (int j=0; j<m; j++) { for (int k=0; k<o; k++) { if (跳出条件) { goto end; } } } } end:
四、函数
(二)函数声明
int f(int a){ return a; } 那么函数的声明可以写成: int f(int a); 或者 int f(int); 特殊的对于返回值和参数都是void的函数,声明可以写成: void f(void);
(三)结构体中的函数(不懂)
如果能在结构体中写函数,那么结构体就更接近一个类了,例子如下:
讯享网struct SHOWDATE{ void (*show)(int year, int month, int day); }; static void show(int year, int month, int day){ printf("%d-%d-%d", year, month, day); } static SHOWDATE showDate={.show=show}; int main(){ showDate.show(2020, 1, 1); return 0; }
五、指针
(一)定义
int a=10; int *p=&a; // (1)(2) *p = 12; // (3) int * const p1; // (4) const int * p2; // (5) int const * p3;
(1)*代表这是一个指针类型。具体到例子中就一个int*类型,代表p存放一个指向int类型的地址
(2)&代表取地址。在例子中就是取int类型变量的地址,即变量a的地址
(3)*p代表一个变量,这个变量就是p所指地址里面的变量
(4)int * const p1;不能修改p里的地址
(5)const int * p2;和int const * p3;不能修改p里地址对应的值
(二)结构体与指针
讯享网typedef strcut stDATE{ int year, month, day; } DATE; int main(){ DATE date1={2020, 1, 1}; DATE* date2=&date1; date1.year=2019; date2->month=2; printf("%d-%d-%d", date1.year, date1.month, date1.day); return 0; } //输出结果date1.month变为2;
(1)结构体变量访问结构体成员使用.,结构体指针变量访问结构体成员使用->。
(三)数组与指针(不懂)
int a[10] = {0} // (1)、(2) int *p = a; // (3) void *q = (void*)p; // (4) int *new = (int*)malloc(10*sizeof(int)); // (5) free(new);
1)int a[10]里面的a实际上是数组第一个变量的地址,所以可以int *p = a;。
(2)*(p+n)与a[n]等价。
(3)int*指针变量加上一个数n,代表指针变量的数值加上n*32(int的bit)得到偏移。
(4)q表示未定的类型(类似char*但不一样)。
(5)使用int*指针变量来创建数组,使用完要free(程序关闭会自动释放,如果程序长时间使用则会造成内存泄露)。
其他:
char c[][]错误;
char c[][10]正确且限制大小;
char *c[]正确,c[n]是一个char*的字符或字符串
char c正确,一个指向指针的指针
六、文件读取
(一)文本文件
函数定义:
讯享网FILE* fopen(const char* restrict path, const char* restrict mode); // 打开文件。参数:路径,模式 int fclose(FILE* stream); // 关闭文件 fscanf(FILE*, ...); // 文件读取(类似scanf,只是加了第一个参数,具体在八) fprintf(FILE*, ...); // 文件输出(类似printf,只是加了第一个参数,具体在八)
fopen的mode选项:
r:只读
r+:读写,从文件头开始
w:只写,清空或新建
w+:读写,清空或新建
a:追加,追加或新建
…x:只新建,若存在则不能打开(wx、ax等)
例子:
FILE* p=fopen("file", "r"); if(fp) { ... fclose(fp); }
二)二进制文件
函数定义(打开文件和关闭文件与文本文件一致):
讯享网// ptr:读入字符串存放的变量、size*nmemb:读多少字符、stream:文件句柄 size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream); size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);
二进制文件读写主要是读写结构体,现在不常用,因为可移植性不好,不如读写文件
七、编译预处理指令与.h文件
(一)编译预处理指令
在c语言中,所有#开头的语句都是编译预处理指令。
c语言编译经过
.c——处理编译预处理指令——》
.i——c编译器编译成汇编文件——》
.s——生成目标代码文件——》
.o——生成可执行文件——》
#.out / .exe
四步得到可执行文件,第一步就是处理编译预处理指令。
1、# include < stdio.h >
# include <stdio.h>就是将stdio.h文件里面的内容复制到代码里面去
2、#define 名称 操作(宏定义)
# define被称为宏定义,格式为# define 名称 操作
例子:
#define PI 3.14159 #define cube(x) (x*x*x) int main(){ cube(3); return 0; }
可以用宏定义定义一个变量PI或一个方法cube。
宏定义定义方法看起来很方便,但十分不推荐初学者使用,因为宏定义的方法是没有类型的,而且运算顺序也不好理解(看上面 二、表达式 15个运算等级的表,就知道多复杂了)。
如果确实想用类似宏定义的方式来定义函数,可以使用下面的方法。
3、(补充)inline内联函数
讯享网inline char *dbtest(int a) { return (a % 2 > 0 ? "奇" : "偶"); }
(二).h文件
(三)一些常用宏
printf("%d", __LINE__); // 输出当前语句行号 printf("%s", __FILE__); // 输出当前文件名 printf("%s", __DATE__); // 输出编译日期 printf("%s", __TIME__); // 输出编译时间 printf("%d", __STDC__); // 当要求程序严格遵循ANSIC标准时该标识符被赋值为1 printf("%s", __FUNC__); // 输出当前函数名
八、常用函数
(一)常用函数
库名 函数定义 解释
默认 size_t sizeof(type_name) 返回byte
string.h size_t strlen(const char *s) 返回s的字符串长度(不包括最后的\0)
string.h int strcmp(const char *s1, const char *s2) 比较两个字符串,返回0:相等; 1:s1>s2; -1:s1<s2
string.h int strncmp(const char *s1, const char *s2, size_t n) 安全版本比较前n个字符的大小,其他同上
string.h char* strcpy(char *restrict dst, const char *restrict src) 把src的字符串拷贝到dst,restrict表示不重叠
string.h char* strncpy(char *restrict dst, const char *restrict src, size_t n) 安全版本,拷贝n个字符,其他同上
string.h char* strcat(char *restrict s1, const char *restrict s2) 把s2拷贝到s1后面,s1要足够大
string.h char* strncat(char *restrict s1, const char *restrict s2, size_t n) 安全版本,追加n个字符,其他同上
string.h char* strchr(const char *s, int c) 在s串中找到c第一次出现的位置,返回指针,没有为null
string.h char* strrchr(const char *s, int c) 在s串中从右边找到c第一次出现的位置,返回指针,没有为nulltring.h
string.h char* strstr(const char *s1, const char *s2) 在字符串s1中不忽略大小写寻找字符串s2
string.h char* strcasestr(const char *s1, const char *s2) 在字符串s1中忽略大小写寻找字符串s2
string.h void *memset(void *s, int c, unsigned long n) 将指针变量s所指向的前n字节的内存单元用一个“整数”c替换
string.h void *memcpy(void *dest, const void *src, size_t n) 从src的开始位置拷贝n个字节的数据到dest。如果dest存在数据,将会被覆盖。
stdlib.h system(“pause”) 暂停程序,按任意键继续
(二)scanf和printf
| flag | 含义 |
|---|---|
| - | 跟width一起用,左对齐(%-9d) |
| + | 正数强制输出正号(%+9d) 可以%±9d/%-+9d |
| 空 | 正常输出 |
| 0 | 数字前填充0(%09d) 不可以%-09d(因为负号已经是左对齐了) |
| width / prec | 含义 |
|---|---|
| number | 最小字符数 |
| .number | 小数点后位数。%9.2f:一共9位,小数点后2位(正数部分7位) |
| * | 将number放到后面作为参数使用(%*d, number, int) |
| .* | 将.number放到后面作为参数使用(%.*d, .number, int) |
| hlL | 含义 |
|---|---|
| hh | 单个字节(char 1byte) |
| h | short(2byte) |
| l | long(4byte) |
| ll | long long(8byte) |
| L | long double(16byte) |
type 用于 含义
i / d int 接受整数值并将它表示为有符号的十进制整数,i是老式写法
u unsigned int 无符号10进制整数
o unsigned int 无符号8进制整数(不输出前缀0)
x / X unsigned int 无符号16进制整数,x对应的是abcdef,X对应的是ABCDEF(不输出前缀0x)
f / F / lf double 单精度浮点数和双精度浮点数用f(lf 在C99开始加入标准,意思和 f 相同)
e / E double 科学计数法表示的数,此处"e"的大小写代表在输出时用的“e”的大小写
g / G double 有效位数,如:%.8g表示单精度浮点数保留8位有效数字。
c char 字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
s / char * / wchar_t * 字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符
p 指针(void *) 以16进制形式输出指针
n 读入/写出的个数(int *) 到此字符之前为止,一共输出的字符个数,不输出文本
% 无 不进行转换,输出字符‘%’(百分号)本身
m 无 打印errno值对应的出错内容,(例: printf("%m\n"); )
原文链接:
【C语言】c语言基础知识梳理(超全)_c语言基础知识必背-CSDN博客

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/120713.html