【问题标题】:Getting "Segmentation fault Core Dumped Error " while reversing a string反转字符串时出现“Segmentation fault Core Dumped Error”
【发布时间】:2015-11-04 12:45:01
【问题描述】:

我正在尝试学习 C,在反转字符串时遇到此错误。我不精通内存分配的东西,请你指出我做错了什么。

#include<stdio.h>
#include<string.h>
char* strrev(char *str);
int main()
{
  char str[1000];
  char *str1;
  printf("Please enter a String\n");
  gets(str);

  str1=strrev(str);
  puts(str1);

}

char* strrev(char *str)
{
  char *str1;
  int i,length,c;
  length=strlen(str);

  for (i=length-1;i<=0;i--)
  {
     *(str1+c) = *(str+i);
     c++;
  }
  *(str1+c) ='\0';
  return str1;

}

【问题讨论】:

  • 不鼓励使用gets,因为此功能无法防止缓冲区溢出。
  • strrev 中的循环永远不会针对长度超过一个字符的字符串运行。对于零长度字符串,您将有 undefined behavior.
  • 与您的错误无关,也许只需检查所有其他已经在 SO 上执行相同操作的帖子,例如 this one?
  • 既然你刚刚开始学习c,现在是学习如何使用GDB的好时机。它是一个调试器,可让您单步执行代码。它可以帮助您了解代码的来龙去脉。它很简单,并且使调试错误变得轻而易举。这是一个简单的启动器:cs.umd.edu/~srhuang/teaching/cmsc212/gdb-tutorial-handout.pdf
  • 你也没有初始化 c,它可能是任何东西。所以你正在写入内存中的一个随机位置。

标签: c string algorithm pointers segmentation-fault


【解决方案1】:
  for (i=length-1;i<=0;i--)

由于i&lt;=0,这将永远不会运行(除非字符串长度为 0 或 1 个字符),应该是 i&gt;=0

通常您还需要将指针指向一些有效的内存,以便能够取消引用它。在您的情况下,您可能应该使用malloc 来分配足够数量的字节,并将其结果分配给str1。然后你就可以照常写了。

【讨论】:

  • 严格来说,不是从来没有。如果字符串str 的长度为零或一怎么办?
  • @MikeCAT:是的,合并
【解决方案2】:

在您的 strrev() 函数中,str1 未分配内存。因此,*(str1+c) = *(str+i);UB

那么,c 是一个自动局部变量,在使用前没有初始化。还有UB。

接下来,as Giorgi mentioned,更正你的 for 循环。

也就是说,不要使用gets(),它会遇到缓冲区溢出问题。请改用fgets()

【讨论】:

    【解决方案3】:

    您要做的不是反转字符串。在您的程序中,这两个字符串都没有反转。您正试图以相反的顺序将一个字符串复制到另一个字符串中。

    所以你要以相反顺序复制原始字符串的字符串应该有足够的空间来存储复制的字符。

    但是在你的函数中

    char* strrev(char *str)
    {
      char *str1
      //...
    

    指针str1 未初始化且未指向适当大小的内存范围。

    所以你的程序有未定义的行为。

    还要考虑到函数gets 是不安全的,C 标准不再支持。请改用函数fgets

    如果您的编译器支持可变长度数组 (VLA),那么程序可以如下所示

    #include <stdio.h>
    #include <string.h>
    
    char * reverse_copy( char *s2, const char *s1 )
    {
        size_t n = strlen( s1 );
        size_t i = 0;
    
        for ( ; i < n; i++ ) s2[i] = s1[n-i-1];
    
        s2[i] = '\0';
    
        return s2;
    }
    
    int main( void )
    {
        char s1[1000];
    
        printf( "Please enter a String: " );
        fgets( s1, sizeof( s1 ), stdin );
    
        size_t n = strlen( s1 );
    
        if ( n != 0 && s1[n-1] == '\n' ) s1[n-1] = '\0';
    
        char s2[n + 1];
    
        puts( s1 );
        puts( reverse_copy( s2, s1 ) );
    
        return 0;
    }
    

    如果以输入为例

    Hello Asfakul Islam
    

    那么输出会是这样的

    Please enter a String: Hello Asfakul Islam
    Hello Asfakul Islam
    malsI lukafsA olleH
    

    否则,如果您的编译器不支持 VLA,您需要动态分配适当大小的数组。在这种情况下,程序可以看起来像下面这样

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    char * reverse_copy( char *s2, const char *s1 )
    {
        size_t n = strlen( s1 );
        size_t i = 0;
    
        for ( ; i < n; i++ ) s2[i] = s1[n-i-1];
    
        s2[i] = '\0';
    
        return s2;
    }
    
    int main( void )
    {
        char s1[1000];
    
        printf( "Please enter a String: " );
        fgets( s1, sizeof( s1 ), stdin );
    
        size_t n = strlen( s1 );
    
        if ( n != 0 && s1[n-1] == '\n' ) s1[n-1] = '\0';
    
        char *s2 = malloc( ( n + 1 ) * sizeof( char ) );
    
        puts( s1 );
        puts( reverse_copy( s2, s1 ) );
    
        free( s2 );
    
        return 0;
    }
    

    【讨论】:

    • 未初始化是什么意思?我需要什么来初始化指针?我应该只分配一个值吗?
    • @AsfakulIslam 您正在使用具有未确定值的指针。您需要 1) 在要写入反转字符串的位置分配内存,以及 2) 通过分配内存的地址分配指针。
    【解决方案4】:
    1. 您没有在strrev() 中初始化str1
    2. 如果输入的字符串长度为 2 个或更多字符,i&lt;=0 为 false,for 循环内的块将不会被执行。
    3. *(str1+c) ='\0'; 会导致崩溃,因为str1 的值是不确定的,您几乎没有机会将str1 指向某个有效位置。

    UPD: strrev() 中的 c 也未初始化,它造成一些麻烦。

    【讨论】:

      【解决方案5】:

      在你的函数中,你没有初始化c

      int i,length,c;
      

      并在for 循环中使用它

      *(str1+c) = *(str+i);
      

      还有其他问题..

      1)str1函数内部没有分配内存。

      2) 这个循环永远不会被执行,因为for (i=length-1;i&lt;=0;i--) 中的条件永远不会为真(除非字符串长度为 0 或 1 个字符)。

      3) 不要使用gets(),它已被弃用。而是使用fgets()

      【讨论】:

      • 如果length&lt;=1i&lt;=0 会变为真。
      猜你喜欢
      • 1970-01-01
      • 2015-12-28
      • 2014-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-22
      • 2019-04-04
      相关资源
      最近更新 更多