问道 C 的基础题

2019-04-14 15:56:09 +08:00
 b00tyhunt3r

对于以下代码段,正确的说法是:


char *p;
while (1)
    {
        p = malloc(1);
        *p = 0;
    }

A. 最终程序会因为没有没有空间了而退出

B. 最终程序会因为向 0 地址写入而退出

C. 程序会一直运行下去

D. 程序不能被编译

主要是内部原理不太明白

5205 次点击
所在节点    C
40 条回复
webdisk
2019-04-14 15:57:54 +08:00
OOM
jxf2008
2019-04-14 16:00:17 +08:00
A
sfqtsh
2019-04-14 16:00:25 +08:00
D.
AngelCriss
2019-04-14 16:04:13 +08:00
当然是选 B 咯,malloc 失败返回 NULL,解引用 NULL 就挂了,如果没有*p = 0,那就看 oom killer 杀不杀,不杀就一直跑。
b00tyhunt3r
2019-04-14 16:08:56 +08:00
@AngelCriss
只有你对了,不过本 noob 第一句就看不懂了,为什么 malloc 会失败,是 OOM 之后才失败吗?姐引用是什么意思?多谢大佬解惑
kljsandjb
2019-04-14 16:18:04 +08:00
@b00tyhunt3r #5 内存 run out 的时候,malloc 返回 null 的情况吧…所以一般会在操作内存的时候最好判断是否空指针,像嵌入式开发这种内存较为稀缺的,这种情况会稍微多见一点,话说这是啥题目啊,这么考感觉非常有中国考试特色啊😂
AngelCriss
2019-04-14 16:24:59 +08:00
模拟一下不就知道了
```
╭─abby@Chameleon /home/abby ‹ system ›
╰─$ cat f.c ↵ 139
#define NULL 0
char memory[10];
int idx = 0;

char* my_malloc()
{
if(idx == sizeof(10))
{
return NULL;
}
char* ptr = memory + idx;
idx += 1;
return ptr;
}

int main()
{
char* p;
while(1)
{
p = my_malloc();
#ifdef MO
*p = 0;
#endif
}
}
╭─abby@Chameleon /home/abby ‹ system ›
╰─$ cc f.c
╭─abby@Chameleon /home/abby ‹ system ›
╰─$ ./a.out
^C⏎ ╭─abby@Chameleon /home/abby ‹ system ›
╰─$ cc f.c -DMO ↵ 130
╭─abby@Chameleon /home/abby ‹ system ›
╰─$ ./a.out
fish: “./a.out ” terminated by signal SIGSEGV (Address boundary error)
╭─abby@Chameleon /home/abby ‹ system ›
╰─$
```
@b00tyhunt3r
webdisk
2019-04-14 16:26:28 +08:00
@kljsandjb 如果一直 malloc(1) 就会出现返回 NULL 的情况, 如果一直 malloc(1024 * 1024) 就会出现 OOM.
返回 NULL 的时候应该是遇到了 glibc 对内存分配的限制, 或者是 linux 内核对内存分配的限制.
b00tyhunt3r
2019-04-14 16:28:48 +08:00
@kljsandjb
浙大幕客题😂😂😂
其实我不太明白的是,
定义一个 char 指针 char *p 之后,分配一个字节内存 p = malloc(1);给 p,此刻在计算机内部 p 的状态是什么样的?
例如 p 自身的位置是 0x100010,
那么此时:
( 1 ) p 指向哪里?
( 2 ) OOM 了之后,malloc 函数返回了 NULL 给 p,此刻得到 NULL 的 p 是个什么状态?又指向哪里?
( 3 )如果我仅仅只是定义了一个 char *p,但什么也不做(或者定义之后程序还没赋值给 p 这段时间内),
此刻的内存里,指针 p 是哪里也不指的状态吗?有这种状态的?

好像教材上没有深入讲
ashlord
2019-04-14 16:35:00 +08:00
@b00tyhunt3r
p 指向属于堆( heap )的某块内存
注意 p 只是一个数值变量,其值恰好是内存地址,所以返回 null 后 p 的值就是 null,即语义上没有指向有效的堆内存。但是由于 c 语言中 null 就是 0,所以会出现对 0 地址写入
仅定义后 p 就是一个未初始化的变量,具体的值是 compiler i mplementation,c 标准应该没有定义。因此常说变量申明后必须初始化才能使用

怎么说呢,不要把指针想的太神秘,它就是一个有特殊意义和操作的数值变量……
alphaprogrammer
2019-04-14 16:35:40 +08:00
malloc 后需要转为目标类型
kljsandjb
2019-04-14 16:36:35 +08:00
@b00tyhunt3r #9 p 分配在栈空间或者寄存器吧,它的值应该是在堆为你开辟的一块空间的起始位置(也就是指向了堆的某个位置)。你这个相当于死循环一直在开空间,你可以了解一下进程地址空间的概念,看看它的结构,程序怎么在进程上下文运行的,栈、堆的概念等都有,推荐一本书:csapp
PureWhiteWu
2019-04-14 16:41:42 +08:00
选 D,没有 include 头文件,编译不过。
kljsandjb
2019-04-14 16:41:45 +08:00
@b00tyhunt3r #9 第三个问题,未初始化的临时变量通常值是不确定的,因为栈始终伴随着程序的调用返回一直在变化,举一个比方,就是刚好一个函数返回,栈指针恢复,但是原先栈中的内容残留了,那么你新建一个临时变量有可能值就是残留的,说白了不用特殊修饰不被优化的临时变量,都是栈地址的表征
fsafdasfsdafsd
2019-04-14 16:51:15 +08:00
我的理解是
malloc 一直分配空间,直到空间满 malloc 分配失败产生 nullptr
wevsty
2019-04-14 16:53:32 +08:00
D
malloc(1)返回的类型是 void*,void*直接赋值给 char*编译器会提示错误。
kljsandjb
2019-04-14 16:58:03 +08:00
@wevsty #16 我记得不强制转换只对指针的运算有限制吧,因为不知道运算的步长,赋值应该不会导致编译期的错误
kljsandjb
2019-04-14 16:58:30 +08:00
@wevsty #16 顶多应该是 warnings 吧
wevsty
2019-04-14 17:20:50 +08:00
@kljsandjb
试了一下,GCC 上 C 方式编译的话是可以过的,CPP 方式的话过不了。
看来是我想当然了。
q8515620
2019-04-14 17:30:58 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/555027

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX