A:问题的根源是因为代码在while循环中改变了 ptr 指针的地址。当输入为'zebra'时,while循环甚至在执行第一遍前就结束了,所以free()释放的内存地址就是一开始malloc()分配的地址。但是当输入'freeze'时, ptr记录的地址在while循环中被更改,因此将会使错误的地址传递到free()方法中引起崩溃。
注意:调用free()方法释放内存时,参数必须要么是NULL,要么是先前从malloc/calloc或者realloc返回的地址,不能将一次动态申请的内存的部分释放。
6 atexit()和_exit()
Q:以下代码中的atexit()方法并没有被调用,直到为什么吗?
#include <stdio.h>
#include <unistd.h>
void func(void)
{
printf("\n Clean up function called \n");
}
int main(void)
{
int i = 0;
atexit(func);
for (; i < 0xFFFF; i++);
_exit(0);
}
A:这是因为使用了 _exit() 方法。此方法并没有调用清除数据相关的方法,比如 atexit()等。exit和_exit都是用来正常终止一个进程的,主要区别是_exit会立刻进入内核,而exit先执行一些清除工作(包括执行各种终止处理程序,关闭所有标准I/O等,一旦关闭了IO,例如printf等函数就不会输出任何东西了),然后才进入内核。这两个函数会对父子进程有一定的影响,当用vfork创建子进程时,子进程会先在父进程的地址空间运行(这跟fork不一样),如果子进程调用了exit就会把父进程的IO给关掉。
7 void*与C结构体
Q:能够设计一个方法接受任意类型的参数然后返回整数?同时,是否有办法传递多个这样的参数?
A:一个能接受任意类型参数的方法像下面这个样子:
int func(void *ptr)
如果需要传递多个参数,那么我们可以传递包含这些参数的结构体。
8 *与++运算符
Q:以下代码将输出什么?为什么?
#include <stdio.h>
int main(void)
{
char *ptr = "Linux";
printf("\n [%c] \n", *ptr++);
printf("\n [%c] \n", *ptr);
return 0;
}
A:程序的输出结果如下:
[L]
[i]
因为++与 * 的优先级一样,所以 *ptr++ 将会从右向左操作。按照这个逻辑,ptr++ 会先执行然后执行*ptr。所以第一个结果是'L'。也因为 ++ 被执行了,所以下一个printf() 结果是'i'。
9 Making changes in code segment
Q:以下代码运行时一定会崩溃,你能说出原因吗?
1 #include <stdio.h>
2 int main(void)
3 {
4 char *ptr = "Linux";
5 *ptr = 'T';
6 printf("\n [%s] \n", ptr);
7
8 return 0;
9 }
A:这是因为字符串常量“Linux”是以只读的形式存储的,而通过*ptr='T'语句,此代码尝试更改只读内存存储的字符串内容,此操作当然行不通,所以才会导致崩溃。
10 Process that changes its own name
Q:你能否写一个程序,在它运行时修改它的名称?
A:以下的代码可以:
1 #include <stdio.h>
2 #include <memory.h>
3
4 int main(int argc, char *argv[])
5 {
6 int i = 0;
7 char buff[100];
8
9 memset(buff, 0, sizeof(buff));
10 strncpy(buff, argv[0], sizeof(buff));
11
12 memset(argv[0], 0, strlen(buff));
13 strncpy(argv[0], "NewName", 7);
14 //Simulate a wait. Check the process name at this point
15 for (; i < 0xFFFFFFFF; i++);
16
17 return 0;
18 }
可以通过下面的方法测试
$ gcc chname.c -o chname
$ ./chname &
[1] 4677
$ ps 4677
PID TTY STAT TIME COMMAND
4677 pts/11 R 0:08 NewName
11 局部变量的返回地址
Q:下面的代码有问题吗?如果有,如何修改?