我想使用指针算法反转字符串。我写了一个小程序,基于我读到的内容" A Book on C"我自己写的基本程序(这让我很满意)。 这是我写的:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
void rv(char* str)
{
int l = strlen(str);
char* copy = (char*) malloc((l + 1) * sizeof(char));
assert(copy != NULL);
int i;
for (i = 0 ; i < l ; i++) { // copy str to copy in reversed order
*(copy + i) = *(str + (l - 1 - i));
}
for (i = 0 ; i < l ; i++) { //
*(str + i) = *(copy + i);
}
free(copy);
printf("Current string is %s\n", str);
}
int main(void)
{
char* s1 = "abcde";
rv(s1);
return 0;
}
程序崩溃了。 根据我的测试,有问题的部分是:
for (i = 0 ; i < l ; i++) { //
*(str + i) = *(copy + i);
}
我读过类似的问题,似乎这一小段代码应该没有坏处。 实际上,即使我用以下内容替换该部分:
*(str + i) = 'c';
该程序仍然崩溃。似乎我甚至无法改变字符串的一个简单字符。 有什么问题?
答案 0 :(得分:3)
这是罪魁祸首:
for (i = 0 ; i < l ; i++) {
*(str + i) = *(copy + i);
}
这会崩溃,因为您将不可写的字符串传递给rv
函数。
要修复,请将正在反转的字符串的内容复制到可写内存中:
int main(void)
{
char s1[] = "abcde";
rv(s1); // No crash here!
return 0;
}
随着崩溃的发生,你可以努力提高算法的效率:不是分配和释放临时字符串,你可以通过在两端开始两个指针,交换它们的内容然后然后转换到位。将它们移向中间。一旦你的指针在中间相遇就停止:
char *s = str;
char *e = s + strlen(str)-1;
for ( ; s < e ; s++, e--) {
char tmp = *s;
*s = *e;
*e = tmp;
}
答案 1 :(得分:2)
C编译器应将字符串文字(在程序中逐字写入的每个字符串,将其包含在撇号内)放在内存的只读区域中。您不能修改它。在C中,了解程序的内存布局非常重要。通过使用以下代码行:
char* s1 = "abcde"
您基本上告诉编译器要做两件事:
创建一个字符串文字&#34; abcde&#34;,将它添加到程序的一个部分中,该部分应该在程序执行时放在只读存储器中。
创建一个名为s1的char指针,您可以在其中存储指向1中创建的字符串文字的内存地址。
由于您要在适当的位置修改字符串,因此必须先将其复制到普通(读写)内存中。这可以通过几种方式完成:
手动,通过在堆上分配读写内存,使用malloc,然后使用strcpy复制字符串:
char *s1 = malloc(strlen("abcde")+1); // +1 for `\0` at the end of string
strcpy(s1, "abcde");
使用C数组初始化程序自动执行:
char s1[] = "abcde";
第二种方式是有效的,因为编译器&#34;魔术&#34; (它将分配适当数量的内存并为您复制字符串)。了解您只能在初始化数组时执行此操作非常重要,但在初始化后您无法执行此操作,因此,这不会起作用:
char s1[];
s1 = "abcde";
另请注意,不能保证字符串文字在只读内存中。一些编译器/系统可能将它们放在一般的读写存储器中。大多数编译器都有一些选项可以做到这一点。但是,如果您希望您的代码与标准C语言兼容并且因此可移植,那么这并不重要。一个好的经验法则是,如果可能的话,在编写代码时应始终尽量避免实现细节。但是知道这种情况何时可能是学习C语言最困难的部分。
答案 2 :(得分:0)
您正在尝试修改const char数组:)
尝试将内存分配为堆栈分配,静态或全局空间。
int main(void)
{
static char s1[] = "abcde";
rv(s1);
return 0;
}
在我的机器上输出:
morten@laptop:/tmp$ clang -Wall t.c
morten@laptop:/tmp$ ./a.out
Current string is edcba
答案 3 :(得分:0)
char* rv(char* s){
char* l=s, *r=s+strlen(s)-1,t;
while(l<r){
t=*l;
*l++=*r;
*r--=t;
}
return s;
}
和ofcose s是指向可写行char的指针。冰川