【问题标题】:Why is my function to reverse string in c not working?为什么我在 c 中反转字符串的函数不起作用?
【发布时间】:2021-05-22 07:01:48
【问题描述】:

我正在编写一些 C 代码,其中用户输入所需的字符串大小,然后是一个字符串,该字符串将被反转然后打印(而不是反向打印。)我还想提一下,我不想使用外部库,重点是能够手动完成。我使用动态内存分配来创建一个由用户输入的大小的字符串,并称为“反向数组”函数。在调用该函数之前一切正常。我反转字符串的方法遵循与反转普通数组相同的原则,但不是移动整数,而是移动字符。你能解释一下我做错了什么吗?

我的代码:

#include <stdio.h>
#include <stdlib.h>

int RvsArr(char *Str, int end)
{
    int start = 0;
    char tmp;
    while (start < end)
    {
        tmp = Str[start];
        Str[start] = Str[end];
        Str[end] = tmp;
        start++;
        end--;
    }
    printf("%s", Str);
    return 0;
}

int main()
{
    int ArrSz;
    printf("Please enter array size: ");
    scanf("%i", &ArrSz);
    char *Str;
    Str = (char *)malloc(ArrSz * sizeof(char));
    printf("Please enter your string: ");
    scanf("%s", Str);
    RvsArr(Str, ArrSz);
    free(Str);
    return 0;
}

【问题讨论】:

  • 您有一个错误。 Str 数组的最后一个有效元素是 str[ArrSz - 1] 而不是 str[ArrSz]。不过可能还有更多问题,我没有检查
  • 这里Str = (char*)malloc(ArrSz * sizeof(char));。我想应该是(ArrSz + 1)*..
  • 对于10Hello 的输入,您期望什么输出?

标签: c reverse c-strings function-definition


【解决方案1】:

您需要反转实际的字符串,而不是整个缓冲区。

char *RvsArr(char* Str)
{
    char *end, *wrk = Str;
    char tmp;
    if(wrk && *wrk)
    {
        end = Str + strlen(wrk) - 1;
        while(wrk < end)
        {
            tmp = *wrk;
            *wrk++ = *end;
            *end-- = tmp;
        }
    }
    return Str;
}

int main()
{
    int ArrSz;
    printf("Please enter array size: ");
    scanf(" %i", &ArrSz);
    char* Str;
    Str = malloc(ArrSz * sizeof(char));
    printf("Please enter your string: ");
    scanf(" %s", Str);
    printf("\n`%s`\n", RvsArr(Str));
    free(Str);
    return 0;
}

https://godbolt.org/z/azob5s

【讨论】:

    【解决方案2】:

    对于初学者,用户可以输入一个字符串,其大小可以小于存储该字符串的动态分配的字符数组的大小。

    所以传递数组的大小没有意义。数组的大小和输入的字符串大小不一样。

    这个表达式 Str[end] 在 while 循环的第一次迭代中访问分配数组之外的内存。

    而且返回类型int也没有意义。

    除此之外,该函数不应输出任何内容。函数的调用者将决定是否输出结果字符串。

    注意这个调用

    scanf("%s", Str);
    

    不安全。使用函数 fgets 会更好。例如

    fgets( Str, ArrSz, stdin );
    

    在这种情况下,您需要删除函数可以附加到输入字符串的换行符'\n'

    在不使用标准字符串函数的情况下,可以通过以下方式定义函数,如下面的演示程序所示。 该函数不是无意义的返回类型int,而是返回一个指向反转字符串的第一个字符的指针。

    #include <stdio.h>
    
    char * RvsArr( char *s )
    {
        char *last = s;
        
        while ( *last ) ++last;
        
        if ( last != s )
        {
            for ( char *first = s; first < --last; ++first )
            {
                char c = *first;
                *first = *last;
                *last = c;
            }
        }
        
        return s;
    }
    
    int main(void) 
    {
        char s[] = "Hello World!";
        
        puts( s );
        puts( RvsArr( s ) );
        
        return 0;
    }
    

    程序输出是

    Hello World!
    !dlroW olleH
    

    如果允许使用标准字符串函数,则函数 RvsArr 可以如下所示(前提是包含标头 &lt;string.h&gt;

    char * RvsArr( char *s )
    {
        char *last = s + strlen( s );
        
        if ( last != s )
        {
            for ( char *first = s; first < --last; ++first )
            {
                char c = *first;
                *first = *last;
                *last = c;
            }
        }
        
        return s;
    }
    

    【讨论】:

      【解决方案3】:

      c 中的字符数组或字符串(通常称为)需要一个额外的字节来存储空字符('\o'0)以指示字符串的结尾。您可以将ArrSz - 1 字符存储在数组中,ArrSz 字节存储终止字符('\o'0)。

      int RvsArr(char* Str, int end)
      {
          if (Str == 0 || end <= 1)
              return 0;
      
          int start = 0;
          char tmp;
          while(start < end)
          {
              tmp = Str[start];
              Str[start] = Str[--end];   // pre decrement the counter to last char
              Str[end] = tmp;
              start++;
          }
          printf("%s", Str);
          return 0;
      }
      

      或其他版本

      int RvsArr(char* Str, int end)
      {
          if (Str == 0 || end <= 1)
              return 0;
      
          int start = 0;
          int last = end - 1;
          char tmp;
          while(start < last)
          {
              tmp = Str[start];
              Str[start] = Str[last];
              Str[last] = tmp;
              start++;
              last--;
          }
          printf("%s", Str);
          return 0;
      }
      

      主要功能的一些变化是

      int main()
      {
          int ArrSz;
          printf("Please enter array size: ");
          scanf("%i", &ArrSz);
          char *Str;
          Str = (char *)malloc(ArrSz * sizeof(char));
          printf("Please enter your string: ");
          scanf("%s", Str);
          Str[ArrSz] = '\0';            // Here we have no control on how many characters are read, scan is a security vulnerability becuse of this
          printf("Input=%s, len=%d\n", Str, strlen(Str));
          RvsArr(Str, strlen(Str));
          free(Str);
          return 0;
      }
      

      【讨论】:

      • '\o' 肯定不是空字符
      • 是的,main() 也需要进行一些更改。
      • @0___________ 是的,main() 也需要进行一些更改。
      • main 不是我的评论
      猜你喜欢
      • 2022-11-06
      • 1970-01-01
      • 2022-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-30
      • 2015-04-22
      • 2021-12-14
      相关资源
      最近更新 更多