C语言面试题---指针篇(二)

C语言指针与内存管理
本文通过两道C语言面试题,详细解析了指针操作中的常见错误及内存管理中的注意事项,帮助读者理解字符串常量不可修改的原则及释放内存后的正确处理方式。
部署运行你感兴趣的模型镜像

版本声明:本文转载于公众号TeachPlus

C语言面试题---指针篇(二)

在上一篇中,我们介绍了关于内存分区的划分,那么现在我们就来看一道跟这个相关的面试题:

阅读下面的程序,找出其中的错误,并说明原因。
# include <stdio.h>
int  main()
{
    char *str = "abcd";
    str[2] = "f";
    printf("%s\n",str);
    return 0;
}

本题解析

答案:该程序会段错误,因为程序中仅仅只定义了一个字符指针,并没有定义字符串,
只是将字符指针指向了“abcd”这个字符串常量了,而字符串常量"abcd"的存储位置是在
内存的数据段(或静态存储区)中的,存储在这个位置的值,是不允许修改的,
因此在程序中使用 str[2] ='f'  试图修改字符串常量的值,就会出现段错误,当然,
我们可能等不到段错误的出现,因为程序在编译阶段就会被报警告了。

相关知识点

静态存储区的作用非常重要,但是对于我们而言最重要的还是栈区和堆区。对于堆区而言,
重要的就是malloc函数和free函数,一起来看一道关于堆区的题目:
阅读下面程序,写出程序的运行结果:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>

void  getMemory( char **p ,  int num)
{
    *p = malloc(num);
}
   int  main()
  {
      char * str = NULL;
      getMemory(&str,100);
      strcpy(str,"hello");
      free(str);
      if(str != NULL)
      {
          printf("%p\n",str);
      }
      return 0;
}
程序运行的结果输出的是指针对象str的值。
在给指针分配内存的时候,其实给指针对象赋了了一个值,这个值就是这片空间的首地址。
随后进行了free操作,free 只是释放的str指向的内存空间,它本身的值还是存在的.
因为内存空间已经被释放了,所以这个指针对象的值,其实是指向没有被分配空间的地址,
如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,

访问这样的越界空间,编译是没有问题的,但是运行时会出现“Segmentation fault”.

所以free之后,有一个好的习惯就是将str=NULL.

不过在该程序中,如果输出str的值,通常还是会打印出hello来。

这是因为,进程中的内存管理理一般不是由操作系统完成的,而是由库函数自己完成的。

当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),
然后在这块空间中记录一些管理信息(一般是在你申请的内存 前面一点),并将可用
内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,
也可以理解成为不会立即清除内存空间中的内容的,因此你是可以继续访问这块地址的。


您可能感兴趣的与本文相关的镜像

Anything-LLM

Anything-LLM

AI应用

AnythingLLM是一个全栈应用程序,可以使用商用或开源的LLM/嵌入器/语义向量数据库模型,帮助用户在本地或云端搭建个性化的聊天机器人系统,且无需复杂设置

<think>好的,用户想要查找与C语言指针相关的面试题。我需要根据之前提供的引用内容来整理相关题目和解析。首先,看看用户提供的四个引用,都是关于C语言指针面试题示例,应该可以从中提取出几个典型的题目。 首先,引用1中的题目涉及数组和指针的操作,特别是数组名和指针运算的区别。这题的结果是2和5,需要解释清楚数组名和指针的类型转换后的差异。 然后,引用2的结构体指针题目涉及到指针运算和类型转换。结构体的大小是20字节,所以p+0x1的地址应该是0x100000 + 20,也就是0x100014。而(unsigned long)p + 1则是数值上的加1,结果为0x100001。unsigned int*类型的指针加1,则增加4字节,所以是0x100004。这部分需要详细说明指针运算和类型转换的影响。 引用3的题目是关于指针数组和指针的操作。pa初始指向数组a的第一个元素,pa++后指向第个元素,即"at",所以输出是at。这个相对简单,但需要解释指针数组和指针的递增操作。 引用4中的题目涉及到字符串指针和strlen函数的使用。这里有几个易错点,比如解引用指针后的行为是否正确,取地址后的随机值问题。需要逐一分析每个printf的输出结果或错误原因。 接下来,我需要将这些题目整理成用户需要的格式,使用中文,并且确保行内公式和独立公式的正确应用。不过这些题目可能不需要数学公式,但如果有涉及地址计算的地方,可能需要使用行内代码或地址表示,比如使用$...$或代码块。 用户要求生成相关问题,但根据示例,可能是指生成更多相关问题,但根据用户的问题,他们可能希望直接看到已有的题目和解析。不过根据用户提供的示例,他们可能希望将现有的引用内容中的题目整理出来,并附上解析,然后生成相关问题。 现在需要按照用户提供的系统级指令来组织回答,包括使用正确的格式,生成相关问题,引用标识等。同时,回答需要结构清晰,帮助用户逐步解决问题。 首先,整理每个引用中的题目,给出解析,然后生成相关问题。例如,引用1的题目解析,引用2的结构体指针问题,引用3的指针数组问题,引用4的strlen问题。然后针对每个题目生成相关问题,如指针运算、类型转换、结构体内存对齐、指针操作等。 需要确保每个解析正确,并正确引用来源。例如,在解析每个题目后,添加对应的引用标识,如[^1]、[^2]等。同时,用户可能需要更多的相关问题,以便他们进一步练习,所以需要根据每个题目的知识点提出相关问题。 最后,检查是否符合用户的所有要求,包括中文回答,LaTeX语法正确,行内代码用反引号包裹,引用标识正确添加,结构清晰等。</think>### C语言指针常见面试题解析 #### 1. 数组名与指针运算差异 **题目**: ```c int main() { int a[5] = {1,2,3,4,5}; int* ptr = (int*)(&a + 1); printf("%d %d", *(a + 1), *(ptr - 1)); return 0; } ``` **解析**: - `a`是数组首元素地址,类型为`int*`,`a + 1`指向第个元素(值为2)。 - `&a`是数组的地址,类型为`int(*)[5]`,`&a + 1`会跳过整个数组(地址增加`5*sizeof(int)`),此时`ptr`指向数组末尾后的位置。 - `ptr - 1`回退一个`int`大小,指向数组最后一个元素(值为5)。 - **结果**:`2 5`。 #### 2. 结构体指针与类型转换 **题目**: ```c struct Test { /* 结构体大小为20字节 */ }* p = (struct Test*)0x100000; int main() { printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); } ``` **解析**: - `p + 0x1`:指针运算按结构体大小(20字节)增加,结果为`0x100014`。 - `(unsigned long)p + 1`:数值运算直接加1,结果为`0x100001`。 - `(unsigned int*)p + 1`:指针类型为`unsigned int*`,加1增加4字节,结果为`0x100004`。 #### 3. 指针数组与指针 **题目**: ```c int main() { char* a[] = {"work","at","alibaba"}; char** pa = a; pa++; printf("%s\n", *pa); return 0; } ``` **解析**: - `a`是字符指针数组,`pa`初始指向`a[0]`(即`"work"`)。 - `pa++`后指向`a[1]`(即`"at"`),`*pa`解引用得到字符串`"at"`。 - **结果**:`at`[^3]。 #### 4. 指针与`strlen`函数陷阱 **题目**(简化): ```c char arr[] = "abcdef"; char* p = arr; // 分析以下表达式的行为: strlen(p); // 6 strlen(p + 1); // 5 strlen(*p); // 错误(类型不匹配) strlen(&p); // 随机值(非字符串地址) ``` **解析**: - `strlen(*p)`:`*p`是字符`'a'`(ASCII 97),将97作为地址访问会导致未定义行为。 - `strlen(&p)`:`&p`是`char**`类型,`strlen`会从指针地址开始读取直到遇到`\0`,结果不可预测[^4]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值