是否有可能在C中修改字符串?
我已经挣扎了好几个小时的各种与指针相关的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 *a = "This is a string"
, char *a = "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");
会输出cello
!)
不,你不能修改它,因为字符串可以存储在只读存储器中。 如果你想修改它,你可以使用一个数组来代替
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
很多人对char *和char []与C中的字符串文字之间的差异感到困惑。当你写:
char *foo = "hello world";
…你实际上是把foo指向一个不断的内存块(实际上,编译器在这个例子中用“hello world”做的是依赖于实现的)。
使用char []来告诉编译器,你想创建一个数组并填充内容“hello world”。 foo是指向char数组的第一个索引的指针。 它们都是char指针,但是只有char []会指向一个本地分配和可变的内存块。
a&b的内存不是由您分配的。 编译器可以自由选择一个只读的内存位置来存储字符。 所以如果您尝试更改它可能导致seg故障。 所以我建议你自己创建一个字符数组。 类似于: char a[10]; strcpy(a, "Hello");
char a[10]; strcpy(a, "Hello");
这似乎是你的问题已经回答,但现在你可能想知道为什么char * a =“String”被存储在只读存储器中。 那么,它实际上是由c99标准没有定义,但大多数编译器选择这样的例子如下:
printf("Hello, World\n");
c99标准(pdf) [第130页,第6.7.8节]:
声明:
char s[] = "abc", t[3] = "abc";
定义“简单的”字符数组对象s和t,其元素用字符串文字初始化。 这个声明与char相同
s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
数组的内容是可修改的。 另一方面,声明
char *p = "abc";
定义p的类型为“指向char的指针”并将其初始化为指向长度为4的类型为“char的数组”的对象,其元素用字符串文字初始化。 如果尝试使用p来修改数组的内容,则行为是不确定的。
你也可以使用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");
所有的答案都是很好的解释,为什么你不能修改字符串,因为它们被放在只读存储器中。 然而,当推动推动时,有一种方法可以做到这一点。 看看这个例子:
#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; }
我已经写了这个作为我在const正确性 ,你可能会发现有趣的(我希望:)) 更深层次的思考的一部分。
希望它有帮助。 祝你好运!
您需要将字符串复制到另一个,而不是只读的内存缓冲区,并在那里修改它。 使用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;
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);