我还是 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*
次迭代
i = 0, ++n
如果我正在使用2D数组,这可以很容易地完成,但他们不是,他们是指针......
我们如何更改此指针中char**
的值?
为什么我们读取此指针中的任何char
而不是写呢?
我还没有完全理解指针,如果代码有问题,请注意,谢谢。
答案 0 :(得分:2)
你在这里得到一个段错误
char* str = (char*)malloc(512);
str = "hello";
*(str) = 'H'; // Segmentation fault
因为您要将ptr
设置为指向字符串文字,即旧值
(由malloc
返回)已经消失。修改字符串文字是未定义的行为和
在大多数系统中,字符串文字无论如何都在只读内存中,所以你不能
修改它们。段错是其结果。
请注意,str = "hello"
是一项作业,您正在复制其中的地址
字符串文字存储在指针str
的内存中。现在str
指向字符串文字。 但是你还没有复制过
内容,因此您需要使用strcpy
或strncpy
之类的功能:
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
指向别的东西。