这是读者在知识星球上写的面试题
我之前写的文章有很完整说过这部分
C语言,函数不可返回指向栈内存的指针
C 语言内存分配
堆和栈的区别(转过无数次的文章)
看完上面的文章,我觉得你至少对C语言程序变量内存有一个概念了解了。
然后看下这几张图
我们想知道一个程序栈的起始地址,我们只需要写个测试程序可以了。
#include "stdio.h" #include "stdlib.h" int main(void) { int a = 3; int *p = (int *)malloc(sizeof(int)); printf("%p\n",&a); printf("%p\n",&p); printf("%p\n",p); return 0; }
我们期望是这样的
实际运行是这样的,跟我们预期符合
0x7ffc3f47e1cc 0x7ffc3f47e1d0 0x562bf8677260
当然,也可以通过一些Linux 命令来查看这些信息
如果还有其他命令大家可以补充
size nm objdump
size 可以看到每个内存段的大小
weiqifa@bsp-ubuntu1804:~/c$ gcc neicunfenpei.c &&size ./a.out text data bss dec hex filename 1802 616 8 2426 97a ./a.out weiqifa@bsp-ubuntu1804:~/c$
nm 可以看到更多的信息,包括里面的地址,还有标识符的区域,想看详细的可以看看man nm。
#include "stdio.h" #include "stdlib.h" int gint = 1; int main(void) { char * pch = "1231231"; int a = 3; int *p = (int *)malloc(sizeof(int)); printf("%p\n",&a); printf("%p\n",&p); printf("%p\n",p); return 0; }
查看输出
weiqifa@bsp-ubuntu1804:~/c$ gcc neicunfenpei.c &&size ./a.out text data bss dec hex filename 1826 620 4 2450 992 ./a.out weiqifa@bsp-ubuntu1804:~/c$ gcc neicunfenpei.c &&nm ./a.out 0000000000201014 B __bss_start 0000000000201014 b completed.7698 w __cxa_finalize@@GLIBC_2.2.5 0000000000201000 D __data_start 0000000000201000 W data_start 0000000000000620 t deregister_tm_clones 00000000000006b0 t __do_global_dtors_aux 0000000000200db0 t __do_global_dtors_aux_fini_array_entry 0000000000201008 D __dso_handle 0000000000200db8 d _DYNAMIC 0000000000201014 D _edata 0000000000201018 B _end 0000000000000814 T _fini 00000000000006f0 t frame_dummy 0000000000200da8 t __frame_dummy_init_array_entry 0000000000000974 r __FRAME_END__ 0000000000201010 D gint 0000000000200fa8 d _GLOBAL_OFFSET_TABLE_ w __gmon_start__ 0000000000000830 r __GNU_EH_FRAME_HDR 0000000000000580 T _init 0000000000200db0 t __init_array_end 0000000000200da8 t __init_array_start 0000000000000820 R _IO_stdin_used w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 0000000000000810 T __libc_csu_fini 00000000000007a0 T __libc_csu_init U __libc_start_main@@GLIBC_2.2.5 00000000000006fa T main U malloc@@GLIBC_2.2.5 U printf@@GLIBC_2.2.5 0000000000000660 t register_tm_clones U __stack_chk_fail@@GLIBC_2.4 00000000000005f0 T _start 0000000000201018 D __TMC_END__
ojbdump 大家可以自己去看看,参数比较多
来看看我们前面说的题目
#include "stdio.h" char * test_function(int n) { int a = 3; char *p1 = "123"; char p2[] = "456"; printf("%p %p %p\n",&a,p1,p2); if(n == 0) return p1; return (char *)p2; } int main(void) { printf("%s\n",test_function(0)); printf("%s\n",test_function(1)); getchar(); return 0; }
这个代码在gcc下是编译会出现警告,而且运行后会出现段错误,因为我们访问了一个非法内存。
weiqifa@bsp-ubuntu1804:~/c$ gcc neicunfenpei.c && ./a.out neicunfenpei.c: In function ‘test_function’: neicunfenpei.c:11:12: warning: function returns address of local variable [-Wreturn-local-addr] return (char *)p2; ^~~~~~~~~~ 0x7fffe549a724 0x5641eaea1874 0x7fffe549a734 123 0x7fffe549a724 0x5641eaea1874 0x7fffe549a734 Segmentation fault (core dumped) weiqifa@bsp-ubuntu1804:~/c$
你以为这就完了?
在devC++下,是可以正常运行的
这个dev C++ 让我觉得有点意思
所以在gcc 下,我们修改下代码
#include "stdio.h" char * pg =NULL; char * test_function(int n) { int a = 3; char *p1 = "123"; char p2[] = "456"; pg = (char *)p2; printf("%p %p %p\n",&a,p1,p2); if(n == 0) return p1; return pg; } int main(void) { printf("%s\n",test_function(0)); printf("%s\n",test_function(1)); getchar(); return 0; }
再运行
没有段错误,但是第二次输出为空!
所以,你下次面试遇到,知道怎么回答了吗?
参考:
https://www.cnblogs.com/ittinybird/p/4657245.html
推荐阅读:
专辑|Linux文章汇总
专辑|程序人生
专辑|C语言
我的知识小密圈
关注公众号,后台回复「1024」获取学习资料网盘链接。
欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~
嵌入式Linux
微信扫描二维码,关注我的公众号