我用各种各样的C教程和与指针相关的书籍一直在苦苦挣扎几个小时,但我真正想知道的是,如果可以在创建一个char指针后更改它。
这就是我的尝试:
char *a = "This is a string";
char *b = "new string";
a[2] = b[1]; // Causes a segment fault
*b[2] = b[1]; // This almost seems like it would work but the compiler throws an error.
那么有没有办法改变字符串内的值而不是指针地址?
由于
编辑:
感谢大家的回答。现在更有意义了。特别有意义的是,为什么有时它工作正常而其他时候不工作。因为有时候我会传递一个char指针,有时会传递一个char数组(char数组工作正常)。
答案 0 :(得分:128)
当你在源代码中写一个“字符串”时,它会被直接写入可执行文件,因为这个值需要在编译时知道(有一些工具可以将软件分开并找到它们中的所有纯文本字符串)。当您编写char *a = "This is a string"
时,“This is a string”的位置在可执行文件中,并且指向的位置位于可执行文件中。可执行映像中的数据是只读的。
您需要做的事情(正如其他答案所指出的那样)是在堆上或堆栈框架中的非只读位置创建内存。如果声明一个本地数组,则在该堆栈上为该数组的每个元素创建空间,并将字符串文字(存储在可执行文件中)复制到堆栈中的该空间。
char a[] = "This is a string";
您也可以通过在堆上分配一些内存,然后使用strcpy()
将字符串文字复制到该空间来手动复制该数据。
char *a = malloc(256);
strcpy(a, "This is a string");
每当使用malloc()
分配空间时,请记得在完成后调用free()
(读取:内存泄漏)。
基本上,您必须跟踪数据的位置。无论何时在源代码中编写字符串,该字符串都是只读的(否则您可能会改变可执行文件的行为 - 想象一下,如果您编写了char *a = "hello";
,然后将a[0]
更改为'c'
然后在其他地方写了printf("hello");
。如果你被允许改变"hello"
的第一个字符,而你的编译器只存储了一次(它应该),那么printf("hello");
会输出{{} 1}}!)
答案 1 :(得分:22)
不,你不能修改它,因为字符串可以存储在只读存储器中。如果要修改它,可以使用数组,例如
char a[] = "This is a string";
或者,您可以使用malloc分配内存,例如
char *a = malloc(100);
strcpy(a, "This is a string");
free(a); // deallocate memory once you've done
答案 2 :(得分:9)
很多人对char *和char []与C中的字符串文字的区别感到困惑。当你写:
char *foo = "hello world";
...你实际上将foo指向一个恒定的内存块(事实上,编译器在这个实例中用“hello world”做的是依赖于实现的。)
使用char []代替告诉编译器你要创建一个数组并用内容“hello world”填充它。 foo是指向char数组的第一个索引的指针。它们都是char指针,但只有char []指向本地分配和可变的内存块。
答案 3 :(得分:6)
& b不是由您分配的。编译器可以自由选择只读存储器位置来存储字符。因此,如果您尝试更改它可能会导致seg错误。所以我建议你自己创建一个角色阵列。类似于:char a[10]; strcpy(a, "Hello");
答案 4 :(得分:3)
似乎您的问题已得到解答,但现在您可能想知道为什么char * a =“String”存储在只读内存中。好吧,它实际上没有被c99标准定义,但是大多数编译器都选择这样的实例,例如:
printf("Hello, World\n");
c99 standard(pdf) [第130页,第6.7.8节]:
宣言:
char s[] = "abc", t[3] = "abc";
定义“plain”char数组对象s和t,其元素用字符串文字初始化。 此声明与char
相同s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
数组的内容是可修改的。另一方面,声明
char *p = "abc";
使用“指向char的指针”类型定义p并将其初始化为指向类型为“array of char”且长度为4的对象,其元素使用字符串文字初始化。如果尝试使用p修改数组的内容,则行为未定义。
答案 5 :(得分:2)
您也可以使用strdup
:
The strdup() function returns a pointer to a new string which is a duplicate of the string s.
Memory for the new string is obtained with malloc(3), and can be freed with free(3).
对于你的例子:
char *a = strdup("stack overflow");
答案 6 :(得分:1)
所有这些都是很好的答案,解释了为什么你不能修改字符串文字,因为它们被放在只读内存中。然而,当推动推动时,有一种方法可以做到这一点。看看这个例子:
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int take_me_back_to_DOS_times(const void *ptr, size_t len);
int main()
{
const *data = "Bender is always sober.";
printf("Before: %s\n", data);
if (take_me_back_to_DOS_times(data, sizeof(data)) != 0)
perror("Time machine appears to be broken!");
memcpy((char *)data + 17, "drunk!", 6);
printf("After: %s\n", data);
return 0;
}
int take_me_back_to_DOS_times(const void *ptr, size_t len)
{
int pagesize;
unsigned long long pg_off;
void *page;
pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize < 0)
return -1;
pg_off = (unsigned long long)ptr % (unsigned long long)pagesize;
page = ((char *)ptr - pg_off);
if (mprotect(page, len + pg_off, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
return -1;
return 0;
}
我已将此作为my somewhat deeper thoughts on const-correctness的一部分写出来,您可能会感兴趣(我希望:))。
希望它有所帮助。祝你好运!
答案 7 :(得分:0)
您需要将字符串复制到另一个而不是只读内存缓冲区并在那里进行修改。使用strncpy()复制字符串,strlen()用于检测字符串长度,malloc()和free()用于为新字符串动态分配缓冲区。
例如(像C ++一样的伪代码):
int stringLength = strlen( sourceString );
char* newBuffer = malloc( stringLength + 1 );
// you should check if newBuffer is 0 here to test for memory allocaton failure - omitted
strncpy( newBuffer, sourceString, stringLength );
newBuffer[stringLength] = 0;
// you can now modify the contents of newBuffer freely
free( newBuffer );
newBuffer = 0;
答案 8 :(得分:0)
char *a = "stack overflow";
char *b = "new string, it's real";
int d = strlen(a);
b = malloc(d * sizeof(char));
b = strcpy(b,a);
printf("%s %s\n", a, b);