使用指针算术反转字符串

时间:2014-04-09 19:13:04

标签: c string pointers

我想使用指针算法反转字符串。我写了一个小程序,基于我读到的内容" 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';

该程序仍然崩溃。似乎我甚至无法改变字符串的一个简单字符。 有什么问题?

4 个答案:

答案 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"

您基本上告诉编译器要做两件事:

  1. 创建一个字符串文字&#34; abcde&#34;,将它添加到程序的一个部分中,该部分应该在程序执行时放在只读存储器中。

  2. 创建一个名为s1的char指针,您可以在其中存储指向1中创建的字符串文字的内存地址。

  3. 由于您要在适当的位置修改字符串,因此必须先将其复制到普通(读写)内存中。这可以通过几种方式完成:

    1. 手动,通过在堆上分配读写内存,使用malloc,然后使用strcpy复制字符串:

      char *s1 = malloc(strlen("abcde")+1); // +1 for `\0` at the end of string
      strcpy(s1, "abcde");
      
    2. 使用C数组初始化程序自动执行:

      char s1[] = "abcde";
      
    3. 第二种方式是有效的,因为编译器&#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的指针。冰川

相关问题