为什么我们可以读取这个分配指针中的任何字符而不写入它?

时间:2018-03-04 20:40:19

标签: c arrays pointers

我还是 C

的新手
char* str = (char*)malloc(512);
str = "hello";
*(str) = 'H'; // Segmentation fault

我在第三行尝试设置一个字符

我知道Segmentation fault指针第一个 str我可以 printf

char

那么,它是否在只读内存中?我不确定为什么会这样,但我可以像我一样改变整个指针

printf("%c\n", *str); // Output: h

我能做到

str = "hello";

从上一个代码,我可以做到这一点,仍然是相同的

char** str = (char**)malloc(512*sizeof(char*));
*str = "hello";
*(str+1) = "Yo!";
//*(str) = 'H';
printf("%s\n", *(str)); // Prints: hello
printf("%s\n", *(str+1)); // Prints: Yo!

原因是它毕竟是一个指针数组,我只是在第一个代码中更改指针,有些索引

以及str[0] = "hello"; str[1] = "Yo!"; 有效的原因,我正在递增*(str+1) = "Yo!";地址或0 索引下一个相邻char*

的地址

从上一个代码中,不能执行

之类的操作
char*

外,如果我有一个 char数组

  **(str) = 'H';

*(str)[0] = 'H';

str[0][0] = 'H';

我可以分配char str[5][10]; // allocated 5 strings slots, 10 max characters for each *(str)[0] = 'H'; *(str[0]+1) = 'e'; str[0][2] = 'l'; str[0][3] = 'l'; *((*str)+4 )= 'o'; printf("%s\n", str[0]); // Prints: Hello 个字符,只需使用512,我可以分配12个字符,但仍然需要更多,我可以内存不足如果我分配太多了

我使用 char * ,我需要能够改变一个 1024的值,就像我在最后一次那样做的阵列

喜欢,让我们说我正在建立一个编译器,文本编辑器...... 我需要能够在运行时分配内存,并检查一些字符,如char

';'函数,split()拆分为<{1}}指针数组

  • 开始将char*复制到char[s]
  • 代表char[n][i] // n = 0, ++i, ++s';'
  • 中的每次char*次迭代
  • return i = 0, ++n

如果我正在使用2D数组,这可以很容易地完成,但他们不是,他们是指针......

我们如何更改指针char**的值?

为什么我们读取此指针中的任何char而不是呢?

我还没有完全理解指针,如果代码有问题,请注意,谢谢。

3 个答案:

答案 0 :(得分:2)

你在这里得到一个段错误

char* str = (char*)malloc(512);
str = "hello";
*(str) = 'H'; // Segmentation fault

因为您要将ptr设置为指向字符串文字,即旧值 (由malloc返回)已经消失。修改字符串文字是未定义的行为和 在大多数系统中,字符串文字无论如何都在只读内存中,所以你不能 修改它们。段错是其结果。

请注意,str = "hello"是一项作业,您正在复制其中的地址 字符串文字存储在指针str的内存中。现在str 指向字符串文字。 但是你还没有复制过 内容,因此您需要使用strcpystrncpy之类的功能:

char* str = malloc(512);
if(str == NULL)
{
    // error handling
    // do not continue
}
strcpy(str, "hello"); // copying the content of the string literal
*(str) = 'H'; // now it works

请注意you don't have to cast malloc。别忘了 检查malloc是否返回NULL并在之后释放内存。

修改

   char str[5][10]; // allocated 5 strings slots, 10 max characters for each
   *(str)[0] = 'H';
   *(str[0]+1) = 'e';
   str[0][2] = 'l';
   str[0][3] = 'l';
   *((*str)+4 )= 'o';
   printf("%s\n", str[0]); // Prints: Hello

这里有一个问题,你没有设置'\0' - 终止 在{byte,printf产生一个未定义的行为。正确的代码应该是:

char str[5][10]; // allocated 5 strings slots, 10 max characters for each
*(str)[0] = 'H';
*(str[0]+1) = 'e';
str[0][2] = 'l';
str[0][3] = 'l';
*((*str)+4 )= 'o';
str[0][5] = '\0'; // terminating the string
printf("%s\n", str[0]); // Prints: Hello

编辑2

  

我们如何更改 C 中指针中的字符的值?

你困惑的问题是你没有意识到你输了 指向malloc ed内存块的指针,并尝试修改字符串文字 代替。

如何更改指针中char的值?

像这样:

char text[] = "This is a long text";
char *ptr = text;
ptr[0] = 't';

这样可行,因为text已使用字符串的内容进行初始化 文字。 ptr指向字符序列的开始 存储在text中,ptr[0]允许您访问中的第一个字符 序列

  

为什么我们读取指针中的任何char而不是呢?

如果您没有权限(例如只读内存)或 指针声明为const,那么你显然不能写一个字符 通过指针。但是如果指针指向有效的可写内存,那么 你可以通过指针写一个字符。

答案 1 :(得分:2)

为了帮助解决你对指针的一些误解,我记下了一些注释(从指针的角度来看)。这并不意味着是滑稽或光顾,但是当我走过去时,从指针的角度来讲,只是有道理。那么让我向您介绍我们的指针p

char *p;

您好,我是一个 uninitialize指针,可以输入char。我只是一个变量,将地址作为我的价值。因此,您可以将您想要的任何地址分配给我,而无需先分配任何内容。例如,

p = "Hello";

我现在将 string-literal “Hello”的地址作为我的值。 “Hello”本身驻留在可执行文件的.rodata部分(只读)。所以你不能改变我现在指出的任何东西。但是,如果我指向的内存是可变的,那么你可以自由地迭代我指向的字符并做出你喜欢的任何改变,例如,

char buf[] = "Hello";
p = buf;

现在我将buf的地址作为我的价值。由于buf存储在堆栈中并且可以自由更改,例如

p[4] = '!';

现在p指向的字符串告诉你不要去。

由于我可以将地址保存到其他任何地方(并且不违反严格别名规则(C11 Standard - §6.5 Expressions (p6,7))),我也可以将起始地址保存到动态分配的块中但是,在我这样做时你必须要小心。在你编写的任何动态分配内存的代码中,你有2 职责关于分配的任何内存块:(1)总是保留一个指针到内存块的起始地址,(2)当不再需要时,它可以释放

这意味着当我指向一个动态分配的块时,你不能为我分配另一个地址,直到你将我指向的地址存储到其他地方,或者free我指向的内存。否则,您将丢失我以前指向的内存的地址,并且永远不会再次释放它(内存泄漏)。

我有另一个重要的角色作为指针。我提供指针算术。我type确定增加,减少或索引时涉及的字节数。由于sizeof char始终为1,因此字符类型上的任何指针算术仅按1-byte递增或递减,但如果我是类型int,则递增或递减移动4-bytes一次{...}},等等......

当您使用我分配存储时,请始终使用我指定的大小来确定分配的大小。例如,分配100 chars

p = malloc (100 * sizeof *p);

如果我指向复合类型,例如

,它的工作方式相同
typedef struct {
    char word[100];
    int nvowels;
} list_t;
...

size_t listsize = 100;
list_t *p = malloc (listsize * sizeof *p);

如果您使用我的尺寸进行分配而不是尝试使用某种类型的尺寸,我会阻止您误解。

所以这几乎是指针的生命中的一天。 (多个间接层的工作方式相同)

答案 2 :(得分:1)

char* str = (char*)malloc(512);
str = "hello";
*(str) = 'H'; // Segmentation fault

然后你说:

  

那么,它是否在只读内存中?我不确定为什么会这样,但我可以像我一样改变整个指针

是的,你字面上改变了整个指针。您现在使str指向只读内存并完全浪费了malloc分配的内存。同样,str = "hello";不会将数据写入malloc提供的内存中。只是让str指向别的东西。