IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言知识点总结 -> 正文阅读

[C++知识库]C语言知识点总结

这是我在学习c语言的时候记的笔记,用作备份与分享(或许也能用作期末复习(笑)),若有错误请在评论区指正,感激不尽!

持续更新中~

C语言文件类型:

filename.h		头文件
filename.c		源文件
filename.i		预处理文件
filename.s		汇编文件
filename.o		目标文件
filename.gch	头文件的编译结果,会优于.h文件调用,建议直接删除
filename.so		共享库文件
filename.a		静态库文件

C语言数据类型:

内建数据类型:

整型数据:

有符号整型:

最高位二进制用于表示正负符号,0代表正数,1代表负数 。

signed char 		1字节		 [-128,127] 
signed short 		2			 [-32768,32767]
signed int 			4 			2开头的十位整数
signed long 		4/8 		//32位系统是4/64位系统是8
singed long long 	8			 9开头的19位整数

占位符:%hhd、%hd、%d、%ld、%lld(自上而下)

注意: 有符号类型数据,signed默认加上。

无符号整型:

所有二进制位都用于表示数据,只能表示整数。

unsigned char 		1字节			[0,256]
unsigned short 		2 				[0,65535]
unsigned int 		4 				[0,4开头的10位整数]
unsigned long	 	4/8
unsinged long long 8 				[0,1开头的20位整数]

占位符:%hhu、%hu、%u、%lu、%llu(自上而下)

**注意:**在定义无符号类型数据时,关键字unsigened不能省略。

浮点数据:

单精度浮点:

float 			4字节		%f

双精度浮点:

double 			8字节 		%lf

高精度浮点:

long double 	12/16 		%LF

浮点型采用科学计数法存储,存储格式为符号位+指数+尾数,运算速度比整型慢。

模拟类型:

char 字符型 在计算机中以整数形式存储,当显示时再根据ASCII码对应关系显示,占位符是%c;

bool 布尔型 包含stdbool.h头文件才可使用

#include <stdbool.h>
bool flag = ture;
bool flag1 = false;

复合数据类型:

结构

由多种内建数据类型组合而成的一个整体,用于描述一个事物的各项数据。由于相同类型的结构体变量数据顺序相同,结构体变量可以直接给结构体变量赋值。

设计结构体:

        Struct Typename
        {
        类型 成员名;
        ...
        };

注意: 此时只是完成了数据类型的设计,一般结构体设计在头文件或函数外,方便其他函数使用(通常结构体Typename首字母大写)。

定义结构变量:

Struct typename 结构变量名;定义时struct不能省略
Struct typename* p = malloc(sizeof(struct typename));使用堆内存定义结构体,使用这种方式,由于编译时堆内存还没有分配,不能进行初始化,只能批量或单个赋值。(p = stu;或scanf(“%s%d%g”,p -> name,&p -> ip,&p -> score)(第一个变量是name,是数组,不取地址))
初始化成员
Struct typename 结构变量名 = {数据1,数据2…}
注意要按照成员顺序进行初始化
Struct typename 结构变量名 =
{
.成员名1 = 数据1,
.成员名2 = 数据2
};
可以无视成员顺序,但要指定成员名
访问成员:
结构变量.成员名;
结构指针 -> 成员名;
例如:typedef struct A{int num;}A; A
a = malloc(sizeof(A)*100) a[5].num或(a+5) -> num;
结构体类型重定义:
由于在C语言中struct关键字无法省略,导致使用时麻烦,可以使用typedef给结构重新定义一个类型。
Typedef struct typename
{

}typename;
结构体字节数计算
系统为了快速的访问结构体的成员,会对结构的成员在内存排列时进行补齐和对齐,因此结构的成员顺序会影响结构的总字节数,一般结构的总字节数会大于等于所有成员的字节数和
对齐:假定第一个成员使用零地址,所有成员所使用的内存地址,必须能被他的字节数整除
补齐:结构体的总字节数必须是它最大成员的整数倍,若不够,则补空字节
在linux系统下,若成员最大字节超过4,则按4计算进行对齐、补齐(windows正常计算)跟系统有关,跟系统位数无关。
Char ch1 : 4将ch以四位二进制(半字节)进行储存,但最终还会进行补齐操作
联合
由程序员设计的一种数据类型,使用语法与结构一样,只是成员的排列方式不同,所有成员共用一个起始位置,共用一块内存,同一时间只能使用一个,一个成员的值发生变化,其他成员的值也会发生变化,可以用一块内存对应多个标识符,达到节约内存的目的,目前已基本不用。没有对齐,有补齐,规则同结构。
Union typename
{
类型 成员名;

};
考点:
成员天然是对齐的,但是有补齐
使用联合判断大小端系统
枚举:一种特殊的整型数据,把一个整型变量可能出现的值全部列出来,并取一个有意义的名字(枚举常量,可以直接放在case里),除此之外不允许使用其他的值(C语言编译器为了提高速度不会检查枚举变量的赋值,但c++会检查)以此来保证数据安全,提高程序的可读性。
Enum direction {up,down,right,lift};默认{0,1,2,3},最好指定初始枚举值。
可以定义匿名枚举,只使用枚举值

运算符

算术运算符 + - * / %
关系运算符 < > <= >= == != 计算结果为0/1(逻辑值,可以继续作为整数参与计算) 使用时常量写左边,变量写右边防止失误将写作=导致不报错但程序出错。
逻辑运算符 && || ! 会先把运算对象转换为逻辑值,0为假,非0为真,结果也是逻辑值 !A 求反,计算对象只有一个,也叫单目运算符,运算级别比&&||高 &&、||具有短路特性,当左边的值可以确定运算结果时,算符右边不进行计算
自变运算符 前自变++i、–i变量值会立即加一或减一 后自变i++、i-- 变量在当前语句不变,下一条语句前会变 只能变量使用,不能过多使用,不同编译器对自变运算符的运算规则不同
三目运算符 [a]?[b]:[c] 运算对象有三个
字节运算符 sizeof() 用于计算数据类型在内存中占用的字节数,仅对一个单位使用时可省略(),如果()内是表达式,不会计算表达式只推算表达式运行结果的数据类型字节数(取可能结果的最大值)。
位运算符 << >> & | ~ ^
类型转换
只有相同类型的数据才能在一起运算
自动类型转换规则:以不丢失数据为基础,字节少的向字节多的转换,有符号向无符号转换,整型向浮点数转换, char和short优先向int转换
强制类型转换: (目标类型)数据,有丢失数据风险
If分支语句
if
else
else if
Switch语句
Switch(整型)
gcc编译器特殊语法:case 1 … 3: => case 1: case 2: case 3:
for循环语句
for([1];[2];[3]) 1:只执行一次 2:条件判断 3:循环体
while循环

随机函数:

#include <stdlib.h>

#include <time.h>

Srand(time(NULL));

Rand()%100+1;(1-100随机数)

数组与函数

数组

一个数组所有数据类型相同所占内存空间大小相同,内存地址连续
数组是最简单最重要的线性结构–顺序结构(特点:内存地址连续)
语法规则:
dataType arrayName[arrayLength]
数组长度是静态的,一旦定义不可改变。const是只读,定义的是变量,C99之前不能使用变量定义长度
如果数组下标超过[0,长度-1]会数组越界,程序不会检查,不会报错但可能改变其他数据的值导致系统出错!!!
变长数组不能直接初始化,需要用循环进行初始化
二维数组
定义 类型 数组名 [行][列]
Int arr[3][5];
初始化语法:
数组名[行数][列数] = {{v00,v01,v02…},{v10,v11,v12…}};

函数

是C语言管理代码的最小单位,是一个代码模块,命名空间、栈空间是独立的。
函数声明:
在C语言中函数名全部小写,用下划线分隔
在函数声明时,形参列表可以只写类型,但在函数定义是必须写全,没有参数时必须写void
不需要返回值时要写void
函数定义 返回值类型 函数名(形参列表) 尽量不要超过50行
传参
普通变量是值传递
数组参数是地址传递,数组会变成指针,需要额外增加一个参数来传递数组长度
不要返回局部变量的地址
函数的隐式声明
如果函数没用显式声明,系统会猜测函数类型
猜测格式
根据实参的个数和类型猜测
返回值int类型
函数的返回值
函数一旦定义的返回值类型,编译器就会划分内存用于存储返回值,而调用者可以访问这部分内存(获取返回值)
return仅能将数据存入返回值的内存,不写return会有随机返回值
函数递归
函数自己调用自己的行为叫递归,没有合适的出口该行为可能导致死循环,有合适的出口可以解决复杂的问题:树形结构问题,带状态的循环,是分治算法的具体实现方式之一
优点:
代码简洁
容易解决复杂问题
缺点:
浪费内存
运行速度慢
递归函数的一般结构
设计出口
解决问题
函数递归

程序的内存分段

Text 代码段:C语言代码会翻译成二进制指令,就存储在该内存中,还有常量(字符串字面值),该内存是只读(可执行)的。一旦强行修改会触发段错误
Data 数据段:存储初始化过的全局变量和静态变量(包括全局和局部)
Bss 静态数据段:未初始化的全局变量和静态变量(包括全局和局部)该内存段在程序执行前会被清理一次(初始化为0)
Heap 堆:由程序员手动管理,范围足够大能存储大量数据,且施放时间可控,该内存无法与标识符建立映射关系(无法取名字),必须与指针配合使用。使用麻烦,容易产生内存泄漏和内存碎片
Stack 栈:存储局部变量使用 size ./a.out可以查看内存大小,由系统自动管理,随函数被调用,会自动分配内存,函数执行结束后,自动释放内存。
优点:使用方便,采用栈结构方式管理,安全,不会产生内存泄漏、内存碎片
缺点:大小有限,一次使用过多可能产生段错误,分配和释放不可控不适合长期保存数据。
变量的分类和属性
(静态)全局变量 生命周期:整个程序运行周期 作用域:任何位置都可以用,但在其他源文件中需要声明(静态全局只能在目标文件内部使用)
(静态)局部变量 生命周期:函数开始执行到结束 作用域:函数内
块变量 定义在for while if等语句块内
变量的属性
作用域:可使用的范围
存储位置:变量存储的内存段
生命周期:定义到释放的时间段
全局变量和局部变量可以重名,局部变量会屏蔽相同名称的全局变量。

变量的类型限制符

Auto 定义自动分配内存、自动翻译内存的变量(默认添加)全局变量不可使用
Const 对变量进行保护,被const修饰的局部变量不能显式修改,可以通过指针隐式修改 特殊情况:存储在data段(初始化后的全局变量)的变量被const修饰后会存储到text段(变量变成常量,无法修改),此时变量被强行修改会出现段错误
Static 限制作用域,改变存储位置,延长生命周期,可以修饰变量也可以修饰函数
限制作用域:限制函数、全局变量的作用域,只能在源文件中使用
延长局部变量的生命周期,改变局部变量的存储位置
Volatile 默认情况下,编译器会优化变量取值过程,使用该类型会使编译器放弃优化(用于变化性高(常被隐式修改)的变量,多线程共享变量,软硬件共享变量)
Register 申请把变量的存储位置从内存改为寄存器,大大提高程序的运行速度,该类型变量不能取地址,但寄存器是有限的,不一定百分百成功
Extern 声明变量,但只是在编译阶段暂时通过,链接时若无法链接到正确的全局变量,会产生未定义错误
Typedef 类型重定义,可以给较长的数据类型重新取一个简短的名字

指针

指针定义:指针是一种数据类型,使用它可以定义指针变量,这种变量存储的是整数,这种整数代表了内存的编号,每个数字对应一个字节,使用指针变量可以访问对应的内存。
指针访问的字节是起始位置,根据指针类型,系统会自动向后访问相应字节的数据,大部分设备是小端设备,即指针起始位置时数据的低位,读取数据时从低位开始读取。
适合使用指针的情况
从理论角度来说,指针可以访问任何位置的内存,但大部分内存没有权限访问,因此非常容易产生段错误,建议仅在合适时(现阶段)使用指针。
函数之间共享局部变量,由于全局变量浪费内存,还可能造成命名冲突,所以全局变量不适合大量共享,而函数传参默认值传递,所以无法共享,使用指针是共享局部变量的好方法。
提高函数的传参效率,函数传参默认值传递(内存拷贝),当变量的字节数较多时,使用指针传递变量的地址效率更高(4(32位系统)或8(64位系统)字节),但这样就带来了变量被修改的风险,可以使用const配合指针保护变量。
配合堆内存使用,堆内存无法取名,无法与标识符建立映射关系,必须与指针配合使用。
指针使用方法
定义指针变量:类型* 指针变量_p;
由于指针变量用法与普通变量不同,为了与普通变量区分,在命名时在结尾加p
指针变量不能连续定义 //int* p1,p2 //p1是指针,p2是int变量 //int *p1,*p2 //二者均是指针
指针变量与普通变量一样,默认值是随机的(野指针),为了安全一定要初始化,可以赋值NULL(空指针)
指针的类型决定了访问内存时的字节数

Char arr[10][10];

Char (*arr)[10];

指针变量的赋值
用变量的地址赋值:p = #
用堆内存地址赋值:p = malloc(sizeof(*p));
指针变量的解引用(访问内存):(*p)指针变量
通过指针变量中存储的内存编号去访问内存,具体访问多个字节由指针变量的类型决定,该过程可能产生段错误,需要从指针赋值的步骤寻找原因
小技巧:当程序崩溃时,内核有可能把该程序当前内存映射到core文件里,方便程序员找到出问题的地方,而ubuntu系统默认不输出core文件,需要执行ulimit -c unlimited,打开bashrc文件(vi ~/.bashrc)在文件末尾添加ulimit -c unlimited然后保存文件运行source ~/.bashrc,可以长期有效。
当出现段错误时,调试时运行gcc -g file.c(出错的文件)指令,然后运行./a.out,gdb ./a.out core,在gdb模式下运行run即可跳转到出错代码段。
退出gdb:运行q
指针的运算
指针变量中存储的是整数,理论上整型能使用的运算符,指针变量都可以使用,但仅有以下运算有意义:
指针 + n;等价于指针+(n乘指针类型字节数)
指针 - n;
指针 - 指针;(指针-指针)/指针类型字节数;不同类型的指针不能相减
使用指针要注意的问题:
空指针:指针变量的值为NULL的指针被称为空指针,大多数系统NULL是0地址,可以把指针变量当逻辑值使用(不建议),不可解引用,否则会产生段错误.为了避免空指针导致的段错误,当使用来历不明的指针时应该判断是否是空指针。
判断空指针 if(NULL == p){ }
野指针:指针变量的值是是随机的、不确定的,这种指针称为野指针,使用野指针不一定会出错、不确定什么时候出错,无法判断一个指针变量是否是野指针,与空指针相比危害性更大。为了避免使用野指针导致的bug,在编程时应避免产生野指针:
定义指针变量一定要初始化
指针变量所指向的内存被释放或销毁后,指针变量要及时赋值为空
函数不返回局部变量的地址
指针与const

const int *p 保护目标,*p不被修改
int const *p 同上
int* const p 保护指针变量p不被修改
const int* const p 既保护p也保护*p
int const * const p 同上
const int const *p 错误写法

指针数组与数组指针
指针数组:由指针变量组成的数组,他的身份是数组,成员是指针变量 int* arr[10];
数组指针:身份是指针,专门用来存放数组的地址 int (*arr)[5]; 数组指针移动以数组字节宽度为一个单位
例:

int arr[] = {1,2,3,4,6}; 
int* p = (int*)(&arr + 1)-1; 
/*&arr为数组指针,宽度为数组宽度,加一后强转为普通指针
长度为int的字节数,所以指向arr[4]	*/
printf(%d”,*p); //输出6

Void指针:
以1字节为单位移动
不能解引用
可以与任何类型的指针自动类型转换,被称作万能指针(C语言限定)
一般被用作函数的参数、返回值
函数指针
函数会被翻译成二进制指令存储到代码段,而函数名就是这段指令的首地址
可以定义特殊的指针变量存储函数的首地址,这样就可以把函数当成数据进行传递
我们把存储函数地址的指针变量叫做函数指针
定义函数指针:
复制函数的声明语句,给函数名加上小括号并在函数名前加*,末尾加p(给函数起一个函数指针名)
Bool (is_prime_p)(int num) = is_prime;
调用is_prime_p(100);
当我们把函数作为数据传递时,被调用的函数可以通过函数指针调用我们以参数形式提供的函数,这种模式叫回调模式。比如:qsort、bsearch
由于函数指针比较长,一般会选择使用typedef进行类型重定义
Typedef int (*FP)(int,int);
FP fp;(fp即是函数指针名,FP相当于函数指针fp的格式)
二级指针
一级指针用于存储普通变量的地址,二级指针用于存储指针变量地址的指针
定义二级指针:类型 ** 变量名_pp;
Int num; int
p = # int** pp = &p;
跨函数共享一级指针时使用二级指针
二级指针解引用:*pp <=> p; **pp <=> *p;
指针与数组的关系
数组名就是数组空间的首地址,是个特殊的指针,是个常量,可以看作常指针,所以可以使用解引用的语法访问成员,指针也可以使用[]进行解引用,所以
Arr[n] <=> *(arr+n)
数组与普通指针区别
数组名是常量,普通指针是变量
普通指针变量有自己的存储空间,用来存储内存编号,它与目标内存是指向关系
数组名没有自己的存储空间,本身就代表数组空间的首地址,它与数组内存是映射关系
对数组名取地址,结果还是数组名的值 int arr[5]
arr<=>&arr
arr类型int*
&arr类型int (*)[5]

堆内存管理

1:C语言中没有管理堆内存的语句,而是由标准库提供的一套函数来管理堆内存:calloc、free、malloc、realloc

Void *malloc(size_t size);

功能:向系统申请一块堆内存

Size:内存块字节数

返回值:

成功 返回内存块首地址

失败 返回NULL

当首次使用malloc申请内存时,malloc会向系统申请内存,而操作系统会一次性给malloc 33页(每页4096字节)内存给malloc管理,之后再使用malloc申请内存时,就会从这33页中分配。

Malloc分配内存时,两个相邻内存块之间存在空隙(至少是4字节,通常4-12)。这些空隙中存在一个指针,这个指针所指向的空间记录着malloc的管理信息,一旦破坏就会影响接下来malloc和free的使用。不要越界,认识内存越界导致的错误。

Void free (void *ptr);

功能:释放内存

可以释放空指针
一块内存不可以重复释放
只释放使用权,而不会清理内存(会破坏一部分数据,并可能监控入口)

操作系统对堆内存的管理决定了是否产生段错误,而malloc、free只是在管理堆内存的使用权限,如果越界访问,会影响malloc和free的后续使用,也可能产生脏数据

Void *calloc(size_t nmemb, size_t size);

功能:按块分配堆内存

Nmemb:要申请的块数

Size:每块的字节数

返回值:内存块的首地址

内存块间无空隙

该函数其实底层调用的malloc,分配的是一整块内存,只是nmemb、size让代码可读性更强,二者调换位置不影响使用结果

Calloc会把分配的内存进行初始化为0,因此速度较慢

Void *realloc(void *ptr, size_t size)

功能:调整已经申请到的内存块的大小,可以变大也可以变小

Ptr:申请到的内存块首地址

Size:要调整到的目标字节数

返回值:

调整后的内存块首地址,如果在原位置基础上无法调整,函数会重新申请一块新的内存块,并把原数据拷贝过去,并释放原内存块

使用malloc申请的内存,里面的内存是随机的、不确定的,如果需要对内存进行初始化,可以使用以下函数

#include <strings.h>

Void bzero(void *s,size_t n)

功能:把一块内存的所有字节赋值为0

S:内存首地址

N:内存块字节数

/**********************************************************************

Void *memset(void *s,int c,size_t n)

功能:把一块内存的所有字节数赋值为c,范围:0-255(以字节为单位)

 #include <stdio.h>

 int main(int argc,const char* argv[])
 {
     int* p = malloc(4);
     int i = 0;
     for(;;)
     {
         printf("%d\n",i);
         p[i] = i++;
     }
 }

为什么可以越界那么多,到33790才越界

Malloc向系统申请内存时,系统会分配给它33页4096字节的空间,其中由4字节用于记录malloc的维护信息,剩下的空间有337914字节的空间,计数从0-33790.

为什么这么设计malloc函数

为了不要频繁访问操作系统,提高效率。

***********************************************************************/

字符:

字符就是符号或团,在c代码是以整数形式模拟的,当需要显示时在根据ascii表中的对应关系显示出对应的符或图案

‘0’ 48

‘A’ 65

‘a’ 97

‘\0’ 0

字符处理相关函数

Int isalnum(int ch);

功能:ch是数字或字母字符,返回非零值,否则返回零

Int isalpha(int ch);

功能:ch是字母,函数返回非零值,否则返回零值

字符串:有字符组成的串型结构(串型结构:由若干个相同类型的数据组成,有一个确定的结束标志,对数据的处理是连续的,直到遇见结束标志) %s

字符串的结束标志是’\0’

字符串字面值:由双引号包含的若干个字符,存储在代码段,以地址形式呈现。

虽然是地址,但与数组名相似,可以计算出字符数量,末尾有隐藏的’\0’,使用sizeof对字面值进行计算可以看出。

可以用 const char* 指针变量来存储它们的地址,长期使用,不能强行修改,否则会产生段错误。

在linux下汉字占三字节,windows下,汉字占两字节

相同的字符串字面值在代码段只存储一份

字符数组:

只要有’\0’结尾,字符数组也就可以当字符串使用。

如果没有’\0’,把字符数组当字符串使用,可能会出现乱码,严重甚至产生段错误

可以使用字符串字面值对字符数组初始化,不需要设置数组长度,编译器会自动计算,并会给’\0’预留位置

字符数组被初始化完成后,程序中就有了两份相同字符串,其中一份存放在代码段,另一份在栈内存,可读可写

字符串的输入:

使用Scanf,占位符%s存储到char*地址,scanf函数会自动在末尾存储’\0’,不会检查字符串存储空间的大小,直到遇见enter,因此输入字符串过长可能会产生段错误。Scanf遇到空格就会停止,无法接受带空格的字符串

Gets(char *s)专门用于接受字符串的函数,同样无法限制输入字符串的长度,当超出存储空间的范围时就可能会产生段错误

Fgets(char *s,int size,FILE *stream)该函数可以从指定的文件中读取不超过size-1个字符,当达到size-1个字符时会自动停止,强行为’\0’预留位置。//终端就是特殊的文件(stdin)

若输入的字符不足size-1,会连同\n一同接收,

如果输入的字符超过size-1个,剩余的数据会残留在数据缓冲区,影响后续数据的输入。解决办法:stdin -> _IO_read_ptr = stdin -> _IO_read_end;

void get_str(char* str,size_t size)

{
    fgets(str,size,stdin);
    size_t len = strlen(str);
    if('\n' == str[len-1])
    {   
        str[len-1] = '\0';
    }   
    else
    {   
        stdin -> _IO_read_ptr = stdin -> _IO_read_end;
    }   
}

输出字符串:

printf()

Puts()功能:输出字符串,自动添加’\n’。返回值输出字符个数

对字符串操作:

标准库中的string.h函数几乎都是处理字符串的函数

常用的有:size_t strlen(const char *s) 计算字符串长度

Char *strcpy(char *dest,const char *src) 拷贝字符串相当于赋值,右边赋值给左边,不负责检查存储空间长度,可能出现段错误

Char *strcat(char *dest,const char *src) 把字符串src追加到dest末尾

Int strcmp(const char *s1,const char *s2) 比较,按照字典顺序排序,谁在前谁小,s1>s2返回正值,s1 < s2 返回负值,s1 == s2 返回0;以上四个函数要求能手写。

Char *strncpy(char *dest,const char *src,size_t n)拷贝n个字符

Char *strncat(char *dest,const char *src,size_t n)把n个字符添加到末尾

Char *strncmp(const char *s1,const char *s2,size_t n)比较前n个字符

Char *strchr(const char *str,int ch) 在str中查找ch首次出现的位置,如果找不到,返回NULL。

Char *strstr(const char *str1,const char *str2)在str1中查找str2首次出现的位置,如果找不到,返回NULL。

Int atoi(const char *nptr)把字符串转换成int整数

long atol(const char *nptr)把字符串转换成long整数

Long long atoll(const char *nptr)把字符串转换成long long整数

预处理指令:

程序员所编写的C代码,并不能被直接编译,而是需要一段程序预先翻译成标准的C代码,负责处理的程序叫做预处理器,处理的过程叫预处理,被翻译的代码叫做预处理指令。所有预处理指令都以#开头
#include 把头文件的内容插入到当前的文件中。
Include <>从系统指定的路径下查找头文件,并插入当前文件
Include”” 先从当前路径下查找头文件,如果没有,再从系统指定的路径下查找头文件,然后插入当前文件。
#define 宏定义指令
定义宏常量:
#define 宏名 (字面值)(末尾没有分号)
给字面值增加一个有意义的标识符,增强可读性和可扩展性
代码在预处理过程中会直接把宏名替换成字面值
定义宏函数
#define 宏名(a,b,c) (a+b+c)
不是真正的函数,而是带参数的宏,预处理时将代码替换成宏名后面的语句,所提供的参数会被替换到语句中的位置
不是真正的函数调用,没有参数传递过程,也没有返回值,运行速度快
不限制参数类型,任何类型都可以使用,代码通用性强
没有类型检查,安全性低
过多使用会造成代码冗余,导致代码段增大,浪费内存
可能会产生二义性
定义宏函数的时候给函数的整体和每一个参数加(),避免产生二义性。
宏函数不能换行,可以使用续行符 \代码
使用宏函数时不要使用自变运算符++/–等
宏函数不能换行,可以使用续行符 \代码\
使用宏函数时不要使用自变运算符++/–等
3)编译时定义宏
Gcc -D DEBUG
4)编译器预定义的宏:
__LINE__计算当前代码的行号
__func__获取当前函数名
__FILE__获取当前文件的名字
__DATE__获取当前日期
__TIME__获取当前时间
_cplusplus 分辨出C语言编译器和C++编译器
③删除宏 #undef
④条件判断
1)#if,#ifdef,#ifndef,#else,#elif,#endif
2)头文件卫士
a.#ifndef #define 内容 #endif 防止头文件重复调用(写头文件的固定格式)
3)代码注释
a.//单行注释,使用麻烦,移植性差早期编译器不支持
b./* */不能嵌套使用
c.#if 0或1 内容 #endif 适合注释大段代码
d.判断代码的编译运行环境
a)#ifdef _cplusplus
b)Printf(“C++编译器”)
c)#else
d)Printf(“C编译器”)
e)#endif
4)调试函数
a.#ifdef DEBUG
b.#define debug(fmt,…)
c.{
d.Printf(“File:%s Line:%d Func:%s Info:”,FILE,LINE,func);
e.Printf(“\033[01;34m”);
f.Printf(fmt,##VA_ARGS);
g.Printf(“\033[00m\n”);
h.}
i.#else
j.#define debug(fmt,…) if(0)
k.#endif
⑤其他预处理指令
1)#error “字符串” 产生一条编译错误信息(不生成可执行文件),与#if系列指令配合使用才有意义。
2)#warning ”字符串” 产生一条编译警告(生成可执行文件),与#if系列指令配合使用才有意义。
3)#line line_number “filename”修改当前代码的行号和文件名
4)#pragma 让编译器执行某些指令,柑橘编译器不同,效果可能不同
a.#pargma pack(n) n=2的n次方才有意义,用于修改结构体内存对齐补齐的最大字节数,n<默认最大字节数。
b.#pragma GCC poison goto/”sta” 禁用某变量或标识符

多文件编程:

1、当程序的业务逻辑越来越复杂,代码量越来越多,所有代码写在一个文件中会影响代码的编写、阅读、团队合作,因此为了避免这个问题,可以按功能把代码编写到不同的源文件中,然后给每个源文件编写一个辅助说明的头文件。
2、头文件应该写什么:
(1)头文件卫士
(2)结构、联合、枚举类型设计
(3)全局变量的声明,在对应的源文件中定义
(4)函数声明,在对应的源文件中实现
(5)宏常量和宏函数
(6)注意:头文件中的内容能在不同的源文件中重复出现而不会导致冲突。源文件一定要包含自己的头文件,为了检查头文件中的函数声明与源文件中的函数定义是否匹配
3、多文件编译
(1)单独把每个源文件生成目标文件,gcc -c file.c会生成file.o
(2)把生成的目标文件合并在一起生成可执行文件,gcc a.o b.o … -o name。
4、Makefile编译脚本
(1)Makefile编译脚本中记录的时项目编译指令的集合,通过make指令批量执行
(2)一般文件中有两大部分内容
①定义变量
1)CC = gcc
2)FLAG = -Werror -Wall
3)OBJS=tools.o cons.o main.o
4)TARGE=cons
②定义编译目标
1)All:
a.$(CC) $(OBJS) -o $(TARGE)
2)Tools.o: $(CC) $(FLAG) tools.c -c
3)Cons.o:
4)Main.o:
③注意使用tab进行缩进,编译目标可以调用其他编译目标,也可以依赖文件,根据目标最后修改时间判断是否需要重新编译.c文件,以此来达到节约编译时间的目的
④可以通过make命令手动调用编译目标,默认只执行第一个编译目标
5、文件读写
(1)文件类型:
①从变成角度,把文件分成两大类:文本文件、二进制文件
②二进制文件:存储数据的补码,无法用文本文件直接打开,好处是读取到文件就可以直接使用
③文本文件:把数据以字符形式存储进去,可以被直接打开,检查数据是否正确,但读写时都需要数据转换
(2)文件的打开操作:
①Fopen(const char* path,const char* mode)功能是打开、创建文件
1)Path文件路径
2)Mode打开模式
a.“r”以只读方式打开文件,如果文件不存在则打开失败
b.“r+”在”r”基础上增加写权限
c.“w”以只写方式打开文件,如果文件不存在则创建,如果文件已经存在则清空内容
d.“w+”在w的基础上增加读权限
e.“a”也是以写权限打开文件,但不会清空文件,如果文件不存在则创建,若存在则将新写入的内容加入到末尾。
f.“a+”在”a”的基础上增加读权限
3)返回值:
a.FILE结构指针,该结构里记录着被打开文件的相关数据,是接下来操作文件的凭证
b.若文件打开失败,则返回NULL。
c.如果文件本身没有相关权限则会打开失败 ,终端下ls -l查看权限
(3)文本文件的读写
①Fprintf(FILE* stream,const char* format,…)功能:以文本格式写入数据到文件
1)Fprintf(fwp,”%s %d %f”,stu.name,stu.id,stu.score);
②Stream:要写入的文件,fopen的返回值
③Format:格式,占位符
④…:要写入的变量
⑤返回值是成功写入的字节数
⑥Fscanf(FILE* stream,const char* fomat,…)
⑦随机读写:每个打开的文件都有一个指针,记录着该文件读写到哪了,该指针被称为位置指针。
1)“r””r+”方式打开的文件,位置指针指向开头,”a””a+”指向末尾,该指针会随文件的读写操作自动移动
2)Fseek(FILE* stream,long offset,int where)
a.功能:设置文件的位置指针
b.Stream:要设置的文件
c.Offset:偏移值
d.Where:基础位置
a)SEEK_SET开头
b)SEEK_END结尾
c)SEEK_CUR当前
e.返回值:成功返回0,失败-1
3)Rewind(FILE *stream)把文件指针指向开头
4)Ftell(FILE stream),获取文件位置指针所指向的字节数。
(4)文件的关闭
①Fclose(FILE
stream)关闭文件。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-14 22:56:44  更:2021-07-14 22:58:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:09:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码