【问题标题】:Char pointer NULL termination and memory allocation [duplicate]Char指针NULL终止和内存分配[重复]
【发布时间】:2019-12-30 17:59:49
【问题描述】:

我有以下程序:我的程序编译良好,并给出如下所述的输出。我对底部列出的输出有一些疑问。 ****************************************************** *****************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    char *p = malloc(sizeof(char));
    char *q = malloc(sizeof(char));
    printf("address of p = %p \n", p); A
    printf("address of q = %p \n", q); B
    strcpy(p, "abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz");
    printf("Value in P : %s \n", p); C
    printf("Value in q : %s\n", q); D
    printf("string length of P : %d \n", strlen(p)); E
    printf("string lenght of q : %d\n", strlen(q)); F

    return 0;
}

===OUTPUT ==
address of p = 0xbbf010 
address of q = 0xbbf030 
Value in P : abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz 
Value in q : 789abcdefghijklmnopqrstuvwxyz
string length of P : 61 
string lenght of q : 29

=====输出结束==

问题:
1.为什么p和q的地址相差32字节。我只为 P 分配了 1 个字节。连续malloc 之间如何自动产生 32 个字节的差异?
2. 我没有NULL 终止我的字符串。 printf如何检测到\0终止?
3. 如果没有\0 终止,strlen 如何也能正常工作?

【问题讨论】:

  • strcpy(p, "abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz"); 调用 未定义的行为 - 你从这段代码得到的任何结果都是没有意义的
  • char *p = malloc(sizeof(char)); = 您分配了 1 个字节并稍后将更长的字符串复制到该地址,因此您正在覆盖随机内存位置(@UnholySheep)并且地址相差超过 1 个字节,因为内存通常分配在对齐的地址上。它的对齐方式因编译器和系统而异,但通常对齐在 4、8、16 或 32 字节边界上。
  • 零终止是由strcpy引起的。查一下:-)
  • @infinite 字符可以从任何字节地址开始,但 malloc 始终分配对齐的存储空间。它选择的对齐方式是未定义的。
  • "abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz" 有一个空值,strcpy 复制了这个空值。

标签: c string char null-terminated


【解决方案1】:
  1. 为什么 p 和 q 的地址有 32 个字节的差异。我只为 P 分配了 1 个字节。32 个字节的差异如何自动 在连续的 malloc 之间?

因为这就是您的实现选择的方式。对malloc() 的任意两次调用的返回值之间没有任何特定关系的要求,即使是像您这样的连续调用也是如此。

在实践中,C 实现倾向于以多字节粒度分配内存,即使请求的大小较小,这就是您所观察到的。这绝对不意味着可以访问超出您明确请求的范围的内存。

  1. 我没有 NULL 终止我的字符串。 printf 如何检测到 \0 终止符?
  2. strlen 如何在没有 \0 终止的情况下也能正常工作?

谁说你的字符串没有终止?字符串文字当然是。除此之外,您会通过超出p 指向的分配空间的边界来产生未定义的行为,因此任何事情都可能发生。

如果您想推测 UB,那么您可能会根据观察到的输出猜测 strcpy 将字节从源字符串复制到从 *p 开始的内存中,继续遍历该和 @ 之间的所有未分配字节987654325@,然后进入*q 之外的未分配空间,直到最终复制 nul 字节。然后您可能会猜到printfstrlen 类似地从一个或另一个起点读取到未分配区域。

这可能会或可能不会准确描述实际发生的情况,在任何情况下,您都不应将观察到的结果解释为此类程序行为是可预测或可接受的指示。特别是,这种行为通常会导致分配器的元数据损坏,这可能会在您尝试释放分配的空间或分配其他空间时表现出来。

【讨论】:

    【解决方案2】:
    1. 您为 pq 分配 1 个字节的存储空间
    2. 您将一个比这长得多的字符串(实际上,任何比空字符串长的字符串都不适合)复制到p,这会触发未定义的行为。

    由于编译器下面的 C std lib(实际上是它的 malloc 实现)似乎选择了 32 字节对齐的分配,并且由于中间没有其他分配发生,因此在您的情况下,这两个指针相隔 32 个字节。

    strcpy 将过长的字符串复制到 p,包括一个零终止符(参见 c 文档)。

    q 将因此指向p + 32 个字节,解释剩余的行为。

    旁注:如果您正在学习 C,尤其是作为初学者,请始终准备好文档。未定义的行为经常发生。

    【讨论】:

      猜你喜欢
      • 2019-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      • 2021-12-12
      相关资源
      最近更新 更多