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

问题描述 投票:1回答:4

我注意到,在用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()时会导致问题。木头下发生了什么?我错过了什么?如何以正确的方式做这些事情?

c arrays string pointers malloc
4个回答
4
投票

你的问题

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

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

a_p = strdup("something");

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

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

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运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为''array of type''的表达式转换为类型为''指针的表达式键入''指向数组对象的初始元素,而不是左值。如果数组对象具有寄存器存储类,则行为未定义。

所以在这个声明之后

a_p = "something";

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

我想你的意思是

strcpy( a_p, "something" );

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

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

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

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

所以if语句

if ( p1 == p2 )

可以产生truefalse


2
投票

那么文字字符串基本上是数组,当你把它分配给a_p时,它会腐烂成指向第一个元素的指针。那个地址正在打印。

因为你没有保留分配的内存的地址,你有内存泄漏。

你也不能在free中使用它,并提供足够的提示,它不是动态分配的。从标准

free函数导致ptr指向的空间被释放,即可用于进一步分配。如果ptr是空指针,则不会发生任何操作。否则,如果参数与内存管理函数先前返回的指针不匹配,或者如果通过调用freerealloc释放了空间,则行为未定义。

这就解释了为什么你在尝试使用未分配的free内存时遇到问题。

再次有类似复制的东西你需要使用strcpystrncpystrdup(符合POSIX)。

有关更多信息,请查看此link。标准明确说明它在翻译步骤中如何被视为数组。

特别是这部分 - (腐朽的指针是char*类型的原因)

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


1
投票

字符串文字"something"表示一系列以空值终止的字符,这些字符位于一些只读区域(如果在GNU / Linux系统上构建/链接/运行,很可能是.text)。

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

使用strcpy(或更好的安全,strncpy)代替将字符复制到目的地a_p

© www.soinside.com 2019 - 2024. All rights reserved.