对malloced字符串的赋值表现得很奇怪

时间:2015-02-26 21:11:52

标签: c

以下是代码,它是C代码。请解释=“string”的返回值

    char * p = (char*) malloc(sizeof(char) * 100);
    p = "hello";   
    *(p+1) = '1';
    printf("%s", p);
    free(p);

6 个答案:

答案 0 :(得分:6)

请注意,p = "hello";不会复制任何字符串,只是将指针p设置为6字节文字字符串"hello"地址。要复制字符串,请使用strncpystrcpy(阅读strncpy(3) ...)但要害怕buffer overflows

所以你做了

 char * p = malloc(100);

分配一个能够容纳100个字节的内存区域。让我们假装malloc成功(读malloc(3) ...)并返回地址0x123456(通常,具体地址不能从一次运行到下一次运行,例如因为{{3} })。

然后你分配p = "hello";,所以你忘记了地址0x123456(你现在有一个ASLR),然后你输入p 6字节文字字符串{{{1}的地址1}}(让我们想象它是0x2468a)。

稍后,机器会执行"hello"的代码,因此您尝试将文件*(p+1) = '1';内的e字符(地址0x2468b)替换为"hello"。您得到memory leak(或其他segmentation violation),因为该文字字符串位于常量只读内存中(例如,您的可执行文件的undefined behavior,至少在Linux上)。

更好的代码可能是:

1

如果你很幸运(没有内存失败)以后输出 #define MY_BUFFER_LEN 100 char *p = malloc(MY_BUFFER_LEN); if (!p) { perror("malloc for p"); exit(EXIT_FAILURE); }; strncpy(p, "hello", MY_BUFFER_LEN); /// you could do strcpy(p, "hello") *(p+1) = '1'; printf("%s", p); free(p); (输出只有在h1llo被刷新时才会发生,因为它是{{3例如,稍后调用stdout)。所以不要忘记致电

fflush

之前的代码块。阅读text segmentbuffered

通用建议是阅读您正在使用的每个函数的perror(3)(即使fflush(3) ...)。

关于 fflush(NULL); 及相关功能,由于printf通常为documentation,实际上我强烈建议您使用stdout -e.g结束每个格式控制字符串。代码中\n;如果你不这样做(有些情况下你不想......)请三思而后行,或者注释你的代码。

不要忘记编译所有警告和调试信息(例如printf("%s\n", p);),然后学习如何使用调试器(例如gcc -Wall -Wextra -g

答案 1 :(得分:2)

您的代码没有按照您的想法执行。

“hello”是幕后指向六个字符的静态数组的指针,很可能是写保护的。

当你将它分配给p时,malloc返回的指针会丢失,而p现在包含一个指向六个字符的静态数组的指针。

对p + 1的分配可能会崩溃,或者可能不会崩溃,但无论它做什么,它都是未定义的行为并且会导致麻烦。

free(p)尝试释放六个字符的静态数组。那不行。再次,未定义的行为,如果你幸运,立即崩溃。

答案 2 :(得分:1)

几乎每行都有问题:
1)在第一行中,您将p分配给新分配的内存的地址。哪个好 2)在下一行中,用一些静态字符串的地址覆盖它。这很糟糕,因为分配的内存会丢失"从而导致内存泄漏 3)在第三行中,您试图覆盖静态字符串位置中的某些内容,这可能是只读的,这很糟糕。
4)在最后一行,你试图释放字符串位置的内存,这是内存违规。

答案 3 :(得分:0)

1)在C中,不正确地强制转换malloc()(C ++,可以转换) 2)分配内存后,p不会为=分配值 strcpy(p,"你好");更好。
3)正确分配后,使用strcpy(),*(p + 1)=' 1'与p [1] =' 1'相同,将导致" h1llo"。

顺便说一下,使用*(p + 1)=' 1' AFTER 使用p ="你好"分配值hello(而不是strcpy())将导致问题,如@gnasher,@ Baile和其他人所描述的那样。

答案 4 :(得分:0)

你需要了解指针是什么。

在C中,没有可以存储字符串的变量。相反,字符串存储在字符数组中。为了能够处理这样的数组,您使用一个变量(称为指针)来存储数组的第一个元素的内存地址。此外,字符串有一个特殊字符(空字符)表示它们结束的位置,但这里没有相关性。

在您发布的代码中,您分配内存来存储100个字符(通常为100个字节)并获取指向此内存区域的第一个元素的指针,称为p(进一步读取:Do I cast the result of malloc?)。

每当使用字符串文字时,会分配一些内存并将其存储在该内存区域中。当你将它分配给p时,p现在指向存储字符串的新内存区域的第一个元素(因此你已经丢失了为malloc分配的内存 - >内存泄漏)。现在,您尝试修改p指向的字符串。这不会起作用,因为字符串文字存储为常量字符串。之后,您尝试释放此字符串的内存,这是不可能的。所有这些错误都会产生运行时错误,并且不容易检测和修复。为了能够实现你想要的,使用像strcpy这样的函数将字符串从只读内存区域复制到指针:

strcpy(p, "string");

答案 5 :(得分:0)

C中的字符串是数组,您不能使用=将值分配给数组,只能分配给数组的索引元素。要复制字符串数据,请使用strcpy()strncpy()。您的代码可能如下所示:

char *p = (char*) malloc(sizeof(char) * 100);
strcpy(p, "hello");   
*(p+1) = '1';
printf("%s", p);
free(p);

试试吧。区别在于p = "hello"将指针p设置为指向常量字符串“hello”,覆盖指向刚刚分配的100字节内存块的指针。下面的free(p);调用将失败,因为您传递的是未由分配函数返回的指针,即使您正在使用的系统在尝试修改常量数据时没有出现写入错误。

如果您确实需要将指针指向常量字符串(它会发生),请确保将指针声明为const char *。这在C ++中是必需的。我不知道在较新版本的C中是否需要它,但无论如何它都是一个真正的好主意。