深入理解C语言

本文深入探讨C语言中的内存区域,详细分析数据类型的本质、指针运算、函数调用模型和栈区特性。同时,介绍了指针在动态内存管理、二级指针、回调函数和字符串操作中的应用,以及结构体、宏定义和动态库封装的知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 面向过程:接口(api)、过程的封装和设计

内存中的四个区域

在这里插入图片描述

数据类型本质分析

  • 数据类型的本质是一个固定内存块大小的别名
  • sizeof是操作符,不是函数;sizeof测量的实体类型的大小为编译期间就已确定。
  • 指针运算的步长和类型有关,比如:
int array[10] = {0};
printf("&array = %p, array = %p, &array+1 = %p, array+1 = %p\n", &array, array, &array+1, array+1);
//前两个输出地址相同,都是array首元素地址值
//第三个输出值比前两个输出地址值大40,因为&array的类型是(int[10])*
//最后一个输出值比前两个地址值大4,因为array的类型是int *
  • void *是万能指针
  • 栈区 vs. 栈:栈区不是栈,栈是一种数据结构,而栈区是一种内存,只不过栈区存放数据的方式是栈的方式(后进先出)。
  • 通过指针在堆区开辟一块内存移动要结合NULL来操作,防止野指针问题。比如:
char *p = NULL;
p = (char *)malloc(100);
if(p == NULL) {
	fprintf(stderr, "malloc error\n");
	return;
}

函数的调用模型

  • 函数调用变量传递分析:
    以在main函数中调用子函数func1、func1中调用func2为例:
    main函数在栈区开辟内存
    main函数在堆区开辟内存

子函数在堆区开辟内存
在这里插入图片描述

总结:

  1. main函数中可以在栈/堆/全局分配内存,都可以被func1和func2使用.
  2. func2在栈上分配的内存,不能被func1和main函数使用
  3. func2中malloc的内存(堆),可以被main和func1函数使用。
  4. func2中全局分配“abcdefg”(常量全局区)内存,可以被func1和main函数使用.
  • 栈的开口方向(或增长方向):向低地址方向生长,即压栈时栈指针减小,退栈时栈指针增大。

指针的进一步理解

  • 段错误(segmentation fault):
  1. 对只读区域进行写操作。比如:char *p = “hello”; p[0] = ‘H’;
  2. 对非访问区域进行读写操作。
  3. stack空间耗尽。 比如:函数内部 int arr[N]= {1}; #define N 100000000
  • 如果要通过函数的参数传递来修改调用函数的变量,那么必须传地址而非传值,从而被调用的函数形参必须为相应类型的指针变量。这对于任意数据类型都成立。比如,要通过一个子函数为main函数动态申请一块堆内存:
int get_mem(int **pp1, int len1) { //在堆区申请一块内存供主函数main使用
	*pp1 = malloc(len1);
	if(*pp1) return 1;
	return 0;
} //本来该函数可以没有返回值,之所以设置一个int型返回值并在结尾返回0是为了以后便于扩展,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值