c语言笔记第四部分

记录一下c语言的学习过程,笔记如有错误,欢迎指出!!!

文章目录

  • 13 内存四区
  • 14.宏函数和普通函数的调用流程
    • 1.calloc 与relloc
  • 15 sscanf的使用
  • 16.链表
    • 1.数组和链表的优缺点
    • 2.带头节点单向链表基本操作
      • 1.链表的初始化,遍历,插入,删除,清空,销毁
  • 17.宏定义
  • 18 动态库和静态库
    • 1.静态链接库
    • 2.动态链接库

13 内存四区

memcpy(dst, src, size):在数据类型位置的情况下,将以src为首地址的size个字节内容copy到以dst为首地址的内存中

内存4区模型:

代码段:.text段。 程序源代码(二进制形式)。

数据段:只读数据段 .rodata段。初始化数据段 .data段。 未初始化数据段 .bss 段。

stack:栈。 在其之上开辟 栈帧。	windows 1M --- 10M	Linux: 8M --- 16M

heap:堆。 给用户自定义数据提供空间。 约 1.3G+

.rodata存放全局常量,不能通过指针修改此值,而局部常量存放在栈中,可以通过指针间接修改

通过malloc,calloc,realloc在栈区开辟的二级指针(二级指针的元素也为开辟的栈区地址)释放时,需要由内向外释放,不然释放不彻底


开辟释放 heap 空间:

void *malloc(size_t size);  申请 size 大小的空间

	返回实际申请到的内存空间首地址。 【我们通常拿来当数组用】

void free(void *ptr);	释放申请的空间

	参数: malloc返回的地址值。

使用 heap 空间:

空间时连续。 当成数组使用。

free后的空间,不会立即失效。 通常将free后的 地址置为NULL。

free 地址必须 是 malloc申请地址。否则出错。

如果malloc之后的地址一定会变化,那么使用临时变量tmp 保存。

14.宏函数和普通函数的调用流程

#define MYADD(x,y) ((x) + (y)

将一些频繁短小的函数 写成宏函数

宏函数优点:以空间换时间,比普通函数在一定程度上效率高,省去了普通函数入、出栈时间的开销

因为宏函数是替换,所以为了保证运算顺序,宏函数需要加括号修饰,

变量,函数入栈,出栈流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9ec3qxn-1721147978070)(https://i-blog.csdnimg.cn/direct/14633b4fc095424384700d410114a7ac.png#pic_center)]

为了解决上面问题,函数的调用方和被调用放对于函数如何调用必须有一个明确约定,这样的约定成为调用惯例

cdecl,C/C++默认调用惯例, C++也可使用stdcall(标准调用惯例)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QOzYAD2D-1721147978072)(https://i-blog.csdnimg.cn/direct/e0bf44d9bc44428da0854716760e9f7d.png#pic_center)]

C语言中,栈顶是低地址,栈底是高地址,高位数据放高地址,低位数据放低地址 –小端对齐

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mu3agD6c-1721147978072)(https://i-blog.csdnimg.cn/direct/8a171e238dc4443b923b5f4a70e193c3.png#pic_center)]

main函数中定义普通变量如 int a = 9; int b = 10 时,int类型占的字节不是4,因为还要存放上下地址,两个int的地址不一定连续

1.calloc 与relloc

//maloc, calloc, realloc 分配的内存连续(个人猜测)
//calloc 分配在堆区,与malloc不同的是 calloc会初始化数据为0
int * p = malloc(sizeof(int)* 10);
int * p = calloc(10, sizeof(int)); 

//realloc  重新分配内存
int * p = malloc(sizeof(int)* 10);
//如果重新分配的内存比原来大,那么不会初始化新空间为0
p = realloc(p, sizeof(int)* 20);

//如果重新分配的内存比原来小,那么释放后序空间,只有权限操作申请空间
p = realloc(p, sizeof(int)* 5);

15 sscanf的使用

%*s或%*d跳过数据
%[width]s读指定宽度的数据
%[a-z]匹配a到z中任意字符(尽可能多的匹配)
%[aBc]匹配a、B、c中一员,贪婪性
%[^a]匹配非a的任意字符,贪婪性
%[^a-z]表示读取除a-z以外的所有字符

1、%*s或%*d 跳过数据

char * str = "12345abcde";
char buf[1024] = { 0 };
sscanf(str, "%*d%s", buf);   //匹配非数字

char * str = "abcde12345"; //忽略遇到空格或者 \t 代表忽略结束
char buf[1024] = { 0 };
sscanf(str, "%*[a-z]%s", buf);
//sscanf(str, "%*s%s", buf);  //全都没匹配,若在e1之间加上空格或\t,可以匹配上

char * str = "12345abcde";
char buf[1024] = { 0 };
sscanf(str, "%6s", buf); //匹配前6个

char * str = "12345abcdeaaa";
char buf[1024] = { 0 };
sscanf(str,"%*d%[a-c]", buf); //只要匹配失败,那么就不继续匹配了, 结果 abc

char * str = "12345abcdeaaa";
char buf[1024] = { 0 };
sscanf(str, "%[0-9]", buf); //只要匹配失败,那么就不继续匹配了, 结果 12345

char * str = "abcCdef";
char buf[1024] = { 0 };
sscanf(str, "%[abC]", buf); //只要匹配失败,那么就不继续匹配了, 结果 ab
	
char * str = "abcCdef";
char buf[1024] = { 0 };
sscanf(str, "%[^C]", buf);  //结果 abc

char * str = "abcCdef123456";
char buf[1024] = { 0 };
sscanf(str, "%[^0-9]", buf);  //结果abcCdef

char * ip = "127.0.0.1";
int num1 = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
sscanf(ip, "%d.%d.%d.%d", &num1, &num2, &num3, &num4);   //sscanf用的是地址,
printf("%d\n", num1);
printf("%d\n", num2);
printf("%d\n", num3);
printf("%d\n", num4);    

char * str = "abcdef#zhangtao@123456";
char buf[1024] = { 0 };
sscanf(str, "%*[^#]#%[^@]", buf);   //结果zhangtao  

char * str = "helloworld@itcast.cn";
char buf1[1024] = { 0 };
char buf2[1024] = { 0 };
sscanf(str, "%[a-z]%*[@]%s", buf1, buf2);  // 第一个%和第三个%做匹配,中间的%不做匹配

16.链表

1.数组和链表的优缺点

数组:

  1. 静态空间,一旦分配内存就不可以动态扩展,如果分配过多,会造成资源浪费
  2. 对于头部插入的效率较低
  3. 索引方便
  4. 内存空间连续

链表:由数据域和指针域构成,数据域维护数据,指针域记录下一个节点的位置

  1. 动态空间,便于分配资源,内存可以动态扩展
  2. 在任何位置插入效率较高
  3. 索引不方便
  4. 占用空间大于数组
  5. 内存空间不连续

链表的分类一

  1. 静态链表:在栈上分配内存
  2. 动态链表:在堆区分配内存

链表的分类二:

  1. 单向链表:每个节点只记录一个地址
  2. 双向链表:每个节点记录两个地址
  3. 单向循环链表:
  4. 双向循环链表:

不带头结点的链表:当进行头插时,第一个节点的地址会改变,链表的访问地址也会改变

带头结点的链表:头节点的地址是固定的,头节点只记录第一个节点的地址

2.带头节点单向链表基本操作

1.链表的初始化,遍历,插入,删除,清空,销毁

见文件夹 链表操作

17.宏定义

注意事项

  1. 宏名一般用大写,以便于与变量区别;
  2. 宏定义可以是常数、表达式等;
  3. 宏定义不作语法检查,只有在编译被宏展开后的源程序才会报错;
  4. 宏定义不是C语言,不在行末加分号;
  5. 宏名有效范围为从定义到本源文件结束;
  6. 可以用#undef命令终止宏定义的作用域;
  7. 在宏定义中,可以引用已定义的宏名;

在项目中,经常把一些短小而又频繁使用的函数写成宏函数,这是由于宏函数没有普通函数参数压栈、跳转、返回等的开销,可以调高程序的效率。
宏通过使用参数,可以创建外形和作用都与函数类似地类函数宏(function-like macro). 宏的参数也用圆括号括起来。

宏定义函数注意事项

  1. 宏的名字中不能有空格,但是在替换的字符串中可以有空格。ANSI C允许在参数列表中使用空格;
  2. 用括号括住每一个参数,并括住宏的整体定义。
  3. 用大写字母表示宏的函数名。
  4. 如果打算宏代替函数来加快程序运行速度。假如在程序中只使用一次宏对程序的运行时间没有太大提高。

例如

防止头文件被重复包含引用

\#ifndef _SOMEFILE_H
\#define _SOMEFILE_H

//需要声明的变量、函数

//宏定义

//结构体

\#endif

特殊宏定义 两边各由两个_

// FILE 宏所在文件的源文件名,
// LINE 宏所在行的行号
// DATE 代码编译的日期
// TIME 代码编译的时间

18 动态库和静态库

库可以简单看成一组目标文件的集合,将这些目标文件经过压缩打包之后形成的一个文件。像在Windows这样的平台上,最常用的c语言库是由集成按开发环境所附带的运行库,这些库一般由编译厂商提供。

1.静态链接库

优缺点:

  1. 静态库对函数库的链接是放在编译时期完成的,静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系;
  2. 程序在运行时与函数库再无瓜葛,移植方便。
  3. 浪费空间和资源,所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

2.动态链接库

要解决空间浪费和更新困难这两个问题,最简单的办法就是把程序的模块相互分割开来,形成独立的文件,而不是将他们静态的链接在一起。简单地讲,就是不对哪些组成程序的目标程序进行链接,等程序运行的时候才进行链接。也就是说,把整个链接过程推迟到了运行时再进行,这就是动态链接的基本思想。

导出函数和内部函数

动态链接库中定义有两种函数:导出函数(export function)和内部函数(internal function)。 导出函数可以被其它模块调用,内部函数在定义它们的DLL程序内部使用

__declspec(dllexport) 用来声名导出函数

24] = { 0 };
sscanf(str, “%[^C]”, buf); //结果 abc

char * str = "abcCdef123456";
char buf[1024] = { 0 };
sscanf(str, "%[^0-9]", buf);  //结果abcCdef

char * ip = "127.0.0.1";
int num1 = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
sscanf(ip, "%d.%d.%d.%d", &num1, &num2, &num3, &num4);   //sscanf用的是地址,
printf("%d\n", num1);
printf("%d\n", num2);
printf("%d\n", num3);
printf("%d\n", num4);    

char * str = "abcdef#zhangtao@123456";
char buf[1024] = { 0 };
sscanf(str, "%*[^#]#%[^@]", buf);   //结果zhangtao  

char * str = "helloworld@itcast.cn";
char buf1[1024] = { 0 };
char buf2[1024] = { 0 };
sscanf(str, "%[a-z]%*[@]%s", buf1, buf2);  // 第一个%和第三个%做匹配,中间的%不做匹配
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值