指向字符串的指针意外更改其值

时间:2017-12-25 18:48:28

标签: c arrays string pointers malloc

我注意到,当在分配有malloc()的数组中写入字符串时,其值会发生变化。要清楚,这是复制这个“错误”的代码:

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

#define N (20)

int main()
{
   char * a_p;
   a_p = malloc( N * sizeof(char));
   printf(" * 01 pointer -> %p\n", a_p);
   a_p = "something";
   printf(" * 02 pointer -> %p\n", a_p);
   printf("-- TEST --\n");
   return 0;

}

执行时,输出为:

 * 01 pointer -> 0x1332010
 * 02 pointer -> 0x4006b9
-- TEST --

虽然我期待相同的值,因为我没有改变指针指向的位置(至少不是直接)。使用free()时会出现问题。木头下发生了什么?我错过了什么?如何以正确的方式做这些事情?

4 个答案:

答案 0 :(得分:4)

您的问题

您正使用malloc()为指针分配内存,但随后将指针变量分配给其他("something",它有自己的地址),而不是填充新分配的指针。 / p>

解决方案

您应该使用分配内存的strdup()函数并在分配的内存中复制字符串:

a_p = strdup("something");

或者strcpy()函数,它将一个malloc()'d指针和一个字符串复制到指向的内存中:

a_p = malloc(N * sizeof(char));
strcpy(a_p, "something");

答案 1 :(得分:3)

您正在直接更改指针。这句话

a_p = "something";

相当于

a_p = &"something"[0];

字符串文字具有字符数组的类型。例如,字符串文字"something"的类型为char[10]

来自C标准(6.4.5字符串文字)

  

6在转换阶段7中,附加一个值为零的字节或代码   每个由字符串文字产生的多字节字符序列   或者文字.78)然后使用多字节字符序列   初始化一个静态存储持续时间和长度的数组   足以包含序列。对于字符串文字,   数组元素的类型为char,并使用   多字节字符序列的各个字节...

在表达式中使用具有罕见异常的数组将转换为指向其第一个元素的指针。

来自C标准(6.3.2.1 Lvalues,数组和函数指示符)

  

3除非它是sizeof运算符或一元&amp;的操作数。   operator,或者是用于初始化数组的字符串文字,a   具有类型''数组类型''的表达式将转换为   带有''指向类型'的指针的表达式,指向初始值   数组对象的元素,而不是左值。如果是数组对象   具有寄存器存储类,行为未定义。

在此声明之后

a_p = "something";

指针指向具有静态存储持续时间的字符串文字的第一个字符。

我认为你的意思是

strcpy( a_p, "something" );

那就是你想在动态分配的内存中复制字符串文字。

考虑到即使您将编写以下代码

char *p1 = "string";
char *p2 = "string";

那么p1不一定等于p2,因为根据编译器选项,编译器可以将这两个相同的字符串文字放在不同的内存范围内。

所以if语句

if ( p1 == p2 )

可以产生truefalse

答案 2 :(得分:2)

当您将文本字符串分配给a_p时,文字字符串基本上是数组,而它会在第一个元素中衰减为指针。那个地址正在打印。

由于您没有保留已分配内存的地址,因此内存泄漏

此外,您无法在free中使用它,并且提供了足够的提示,表示它未动态分配。从标准

  

free函数导致ptr指向的空间   取消分配,即可用于进一步分配。如果是ptr   空指针,不会发生任何操作。 否则,如果参数没有   匹配之前由内存管理函数返回的指针,或   如果通过拨打freerealloc取消分配空间,则   行为未定义。

这就解释了为什么你在尝试free记忆时遇到了问题。

再次要复制,您需要使用strcpystrncpystrdup(符合POSIX)。

有关详情,请查看 link 。标准明确说明它在翻译步骤中如何被视为数组。

特别是这部分 - (腐朽指针的类型为char*,这就是为什么)

  

对于字符串文字,数组元素具有类型   char,并使用多字节的单个字节进行初始化   字符序列。

答案 3 :(得分:1)

字符串文字"something"表示存在于某个只读区域中的以空字符结尾的一系列字符(如果您在GNU / Linux系统上构建/链接/运行,则很可能是.text)。

最初,a_p指向内存区域中malloc正在分配缓冲区的某个位置。您可以自由地写入a_p点,free()等的位置。当您执行作业a_p = "something";时,您不会将字符写入{{1}的位置}指向,而是将指针更改为指向该字符串的开头。现在,您指向a_p未分配的(只读)内存,因此其对应的malloc函数无法执行任何有意义的操作。

使用free(或者更安全,strcpy)而不是将字符复制到目的地strncpy