C语言-const-static-指针-内存

本文深入探讨了C语言的关键概念,包括const与static修饰符的使用、指针的各种类型及应用、函数指针的实现、内存管理技巧如malloc与calloc的区别、一维与二维数组的动态内存分配、数组指针与指针数组的区别以及枚举类型的运用。

const

普通变量

const是定义静态变量,变量不可修改
static将变量的作用域限制到此文件或函数
其中int const static三个关键词的地位相同,顺序可交换,即int const num;和 const int num 一个意思。

	int const num = 100;
	int const static num2 = 200;
	//num = 10; 此句话error

指针变量

	int a=10;
	int b=11;
	int c=12;
	
	//静态指针
	int const *pa = &a;	//*pa是一个常量,指向地址的值不能变化
	int * const pb = &b;//pb是一个常量,指针无法更改指向的地址,但可以更改指向地址里的值
	int const* const pc = &c;//*pc和pc都是常量,都无法更改

函数指针

typedef int * (*PFUNC)(int, char*);
	
int* ccstr(int n, char * str) {
	printf("str func! \r\n");
	printf("%s \r\n", str);
	return NULL;
}
int main()
{	
	PFUNC pf2;
	pf2 = ccstr;
	pf2(1, "pfunc test");
	//这样既可使用指针调用函数。
	return 0;
}

内存申请与释放

malloc与calloc功能相同,函数入口参数不同,calloc方便阅读些。函数反馈的变量都是viod*型,所以需要类型转换。

一维数组或指针的申请

	int* p;
	int size = 10;
	//p = (int *)malloc(size * sizeof(int));	//申请内存空间
	p = (int *)calloc(size, sizeof(int));		//申请内存空间
	p = realloc(p, 100 * sizeof(int));			//重新分配p的内存空间
	if (p == NULL) {
		printf("malloc size is NULL\r\n");
		return -1;
	}
	free(p);

二维数组或指针的申请

	int ** pint;
	
	pint = (int**)malloc(sizeof(int*)*size);
	if (pint  == NULL) {
		printf("malloc size is NULL\r\n");
		return -1;
	}
	//申请总的后需要给各个部分申请地址
	for (i = 0; i < size; i++)
	{
		pint[i] = (int*)malloc(sizeof(int)*size);
	}
	//free时候先释放小的在释放总的
	for (i = 0; i < size; i++)
	{
		free(pint[i]);
	}
	free(pint);

数组指针与指针数组

	int num[2][5] = {0,1,2,3,4,5,6,7,8,9};
	int num2[2][5] = {0,1,2,3,4,5,6,7,8,9};
	int* p1[2];
	p1[0] = &num[0];
	p1[1] = &num[1];
	printf("%d %d %d \n", *p1[0], *(p1[0] + 1), *(p1[0] + 2));
	printf("%d %d %d \n", *p1[1], *(p1[1] + 1), *(p1[1] + 2));

在这里插入图片描述
指针地址加1,则输出数组的下一个值,地址变化为1个int,即一次加1,变化4个字节。

	int num2[2][5] = {0,1,2,3,4,5,6,7,8,9};
	int (*p2)[5];
	p2 = &num2;
	printf("%d  \n", p2++);
	printf("%d  \n", p2++);
	printf("%d  \n", p2++);

打印出p2地址变化为:
在这里插入图片描述
(*p2)[4]表示数组指针(也称行指针),一次++增加了20个字节,由于int是4字节,则增加了5个int,也就是说执行p+1时,p要跨过n个整型数据的长度。

*p1[4]表示指针数组,相当于是一个二维指针或者二维数组。
(*p2)[4]表示数组指针(也称行指针),指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

枚举类型

	enum int{
	num1,num2,num3
	};
	//相当于 
	int num1;
	int num2;
	int num3;

	typedef int COLOR;
	enum COLOR{
	White,Black,Green
	};
	enum COLOR num;
	num = 0;
	switch (num)
	{
	case White:	printf("White \r\n");
		break;
	case Black:	printf("Black \r\n");
		break;
	case Green:	printf("Black \r\n");
		break;
	default:	printf("NULL \r\n");
		break;
	}

使用枚举的好处显而易见,switch case语句只能使用常量,如果用const定义的静态静态变量,虽然值不会改变,但是也属于变量,不可用于case,但enum定义的是常量,可用于case。

<think>我们正在讨论C语言中的staticconst关键字组合。根据引用内容,我们可以总结如下:1.**static关键字的作用**:-修饰局部变量:使其存储在静态存储区,生命周期延长至整个程序运行期间,且只初始化一次。若未显式初始化,则编译器自动初始化为0。该变量具有"记忆性",在函数多次调用间保持值不变[^2][^3]。-修饰全局变量或函数:将其作用域限制在当前文件内(内部链接),避免与其他文件的同名变量或函数冲突[^2][^3]。2.**const关键字的作用**:-定义常量,被修饰的变量不可修改,增强程序健壮性。-通常用于函数形参(尤其是指针),防止函数内部意外修改指针指向的数据[^1]。-编译器通常不为普通const常量分配存储空间,而是保存在符号表中,提高访问效率[^2]。3.**staticconst组合**:-同时具有staticconst的特性:-**作用域**:若修饰全局变量,则作用域仅限于当前文件(static特性)。-**存储与生命周期**:存储在静态存储区,生命周期为整个程序运行期(static特性)。-**不可修改性**:值不可修改(const特性)。-典型应用场景:定义仅在当前文件内可见的常量。###示例代码```c//文件file.cstaticconstintMAX_VALUE=100;//当前文件私有的常量voidfunc(){staticconstfloatPI=3.14;//函数内静态常量,不可修改且具有记忆性//PI=3.15;//错误:const禁止修改}```###注意事项-**初始化**:`staticconst`变量必须在定义时初始化(因const要求初始化,且static要求仅初始化一次)。-**效率**:编译器可能优化为直接内联值,避免内存访问。---§§相关问题§§1.`staticconst`与`#define`定义的常量有何区别?2.在头文件中使用`staticconst`是否安全?3.`staticconst`能否用于修饰函数参数?</think>### C语言中 `static const` 的用法与作用 `static const` 是 C 语言中结合了 `static` 和 `const` 两个关键字的复合用法,具有以下核心特性: #### 一、核心作用 1. **定义文件级私有常量** - `static` 限制作用域仅在当前文件内 - `const` 确保值不可修改 ```c // file1.c static const int MAX_SIZE = 1024; // 仅在 file1.c 中可见且不可修改 ``` 2. **函数内持久化常量** - `static` 使局部变量生命周期延长至程序结束 - `const` 保证初始化后值不变 ```c void calculate() { static const double PI = 3.1415926; // 只初始化一次,不可修改 // 后续调用会保留 PI 的值 } ``` #### 二、关键特性对比 | 特性 | `static` | `const` | `static const` 组合效果 | |---------------------|-----------------------------------|----------------------------------|----------------------------------| | **作用域** | 文件内可见 | 取决于声明位置 | 文件内可见 | | **存储位置** | 静态存储区 | 可能被编译器优化(符号表) | 静态存储区 | | **生命周期** | 整个程序运行期 | 取决于作用域 | 整个程序运行期 | | **值可变性** | 可修改 | 不可修改 | **不可修改** | | **初始化要求** | 定义时可不初始化(默认0) | **必须初始化** | **必须初始化** | #### 三、典型应用场景 1. **头文件中的常量定义** ```c // utils.h static const int BUFFER_SIZE = 256; // 每个包含该头文件的.c文件获得独立副本 ``` 2. **防止函数内常量重复初始化** ```c int get_counter() { static const int INIT_VAL = 10; // 仅首次调用时初始化 return INIT_VAL; } ``` 3. **硬件寄存器映射**(嵌入式开发) ```c static const volatile uint32_t* UART_REG = (uint32_t*)0x4000F000; // static const 保证指针常量性,volatile 防止编译器优化 ``` #### 四、与 `#define` 的区别 | 特性 | `#define` | `static const` | |---------------|----------------------|-------------------------| | 类型检查 | 无 | 有 | | 调试可见性 | 预处理阶段替换 | 符号表中保留 | | 作用域 | 全局 | 文件级/函数级 | | 内存占用 | 不分配内存 | 可能占用静态存储区 | > 建议:需要类型安全和调试可见性时优先使用 `static const`,简单字面量可考虑 `#define`[^1][^3] ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值