C语言可以直接操作内存。这是一把双刃剑。如果不想造成混乱,唯一的解决办法就是去了解它熟悉并应用它。
一、void关键词。
- void 的字面意思是“空类型”
- void *则为“空类型指针”,void *可以指向任何类型的数据。
二、C语言内存的印象。
- 代码(code area),存放函数体的二进制代码;
- 数据(data area),存放未初始化的全局变量和静态变量。程序结束后由系统释放;
- BBS(Block Started by Symbol),存放已初始化的全局变量、静态变量、字符串常量。程序结束后由系统释放;
- 堆(heap area),存放程序运行中动态分配的存储空间。堆是低地址向高地址扩展的数据结构,是一块不连续的内存区域。在标准C语言上,使用malloc等内存分配函数是从堆中分配内存,同时需要手动分配释放内存。未及时释放产生内存泄漏;
- 栈(stack area),存放程序临时创建的局部变量,其中还包括函数调用时其形参,调用后的返回值等。栈是由到高地址向低地址扩展的数据结构。块执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
三、C语言内存操作函数。
- malloc函数,向系统申请分配指定 size 个字节的内存空间。
- calloc函数,向系统申请分配 count 个长度为 size 一共为 count 乘以 size 个字节长度的连续内存空间,并将每一个字节都初始化为 0。
- realloc函数,更改已经配置好的内存空间到指定的大小。
- free函数,表示用来释放已经动态分配的内存空间。
free()
可以释放由malloc()
、calloc()
、realloc()
分配的内存空间,以便其他程序再次使用。
#include <stdio.h>
#include <malloc.h>
int main()
{
// malloc, void *malloc(size_t_Size).
int* a = (int*)malloc(4);
printf("1. malloc, a is %d.n", *a);
*a = 56000;
printf("2. malloc, a is %d.n", *a);
// calloc, void *calloc(size_t_Count, size_t_Size).
// 用来定义数组。默认值为0。
int* b = (int*)calloc(3, 4);
printf("3. calloc, b[0] is %d.n", b[0]);
b[0] = 10;
printf("4. calloc, b[0] is %d.n", b[0]);
// realloc, void *realloc(void *_Block, size_t_Size).
// 内存空间变小,产生溢出。
realloc(a, 2);
printf("5. realloc, a is %d.n", *a);
// free, void free(void *).
free(a);
free(b);
// 显示使用未定义变量的错误。
// printf("7. free, a is %d, b[0] is %d.n", *a, b[0]);
}
/*
控制台输出
————————————————————
1. malloc, a is -842150451.
2. malloc, a is 56000.
3. calloc, b[0] is 0.
4. calloc, b[0] is 10.
5. realloc, a is -33695040.
*/
四、错误处理。
我们学习其它语言,发现错误处理非常重要,但C 语言没有提供对错误处理的直接支持。C语言允许你访问底层数据,在发生错误时,大多数的 C 或 UNIX 函数调用时返回1或 NULL,同时会设置一个错误代码errno,该错误代码是全局变量,表示在函数调用期间发生了错误。您可以在 errno.h 头文件中找到各种各样的错误代码。
- perror() 和 strerror(),C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。
- perror() 函数,显示你传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
- strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno;
int main()
{
FILE* pf;
int code;
char err[256];
fopen_s(&pf, "not_exist.file", "rb");
if (pf == NULL)
{
code = errno;
// VS里使用strerror_s替代strerror。
strerror_s(err, 256, code);
printf("file open is err, %d, %s.", code, err);
}
else
{
fclose(pf);
}
return 0;
}
/*
控制台输出
————————————————————
file open is err, 2, No such file or directory.
*/
五、命令行参数。
执行程序时,可以从命令行传值给 C 程序,这些值被称为命令行参数。命令行参数是使用 main() 函数参数来处理的,其中,argc 是指传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数。
下面示例来自菜鸟教程。
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc == 2)
{
printf("The argument supplied is %s.n", argv[1]);
}
else if (argc > 2)
{
printf("Too many arguments supplied.n");
}
else
{
printf("One argument expected.n");
}
}
/*
控制台输出
————————————————————
One argument expected.
*/
C语言的一些标准库就不介绍了。
下一章,学C语言写自己的K语言:编译器简介。
让我们在这里,遇见明天的自己!姜友华