【问题标题】:strcat adds junk to the stringstrcat 将垃圾添加到字符串中
【发布时间】:2020-04-19 08:52:55
【问题描述】:

我正在尝试颠倒一个句子,而不改变单词的顺序,

例如:“Hello World”=>“olleH dlroW”

这是我的代码:

#include <stdio.h>
#include <string.h>

char * reverseWords(const char *text);
char * reverseWord(char *word);

int main () {
  char *text = "Hello World";
  char *result = reverseWords(text);
  char *expected_result = "olleH dlroW";
  printf("%s == %s\n", result, expected_result);
  printf("%d\n", strcmp(result, expected_result));
  return 0;
}

char *
reverseWords (const char *text) {
  // This function takes a string and reverses it words.
  int i, j;
  size_t len = strlen(text);
  size_t text_size = len * sizeof(char);
  // output containst the output or the result
  char *output;

  // temp_word is a temporary variable,
  // it contains each word and it will be
  // empty after each space.
  char *temp_word;

  // temp_char is a temporary variable,
  // it contains the current character
  // within the for loop below.
  char temp_char;

  // allocating memory for output.
  output = (char *) malloc (text_size + 1);

  for(i = 0; i < len; i++) {

    // if the text[i] is space, just append it
    if (text[i] == ' ') {
      output[i] = ' ';
    }

    // if the text[i] is NULL, just get out of the loop
    if (text[i] == '\0') {
      break;
    }

    // allocate memory for the temp_word
    temp_word = (char *) malloc (text_size + 1);

    // set j to 0, so we can iterate only on the word
    j = 0;

    // while text[i + j] is not space or NULL, continue the loop
    while((text[i + j] != ' ') && (text[i + j] != '\0')) {

      // assign and cast test[i+j] to temp_char as a character,
      // (it reads it as string by default)
      temp_char = (char) text[i+j];

      // concat temp_char to the temp_word
      strcat(temp_word, &temp_char); // <= PROBLEM

      // add one to j
      j++;
    }

    // after the loop, concat the reversed version
    // of the word to the output
    strcat(output, reverseWord(temp_word));

    // if text[i+j] is space, concat space to the output
    if (text[i+j] == ' ')
      strcat(output, " ");

    // free the memory allocated for the temp_word
    free(temp_word);

    // add j to i, so u can skip 
    // the character that already read.
    i += j;
  }

  return output;
}

char *
reverseWord (char *word) {
  int i, j;
  size_t len = strlen(word);
  char *output;

  output = (char *) malloc (len + 1);

  j = 0;
  for(i = (len - 1); i >= 0; i--) {
    output[j++] = word[i];
  }

  return output;
}

问题是我用&lt;= PROBLEM标记的那行,在这种情况下是“你好”的第一个词,它做的一切都很好。

在本例中是“世界”的第二个单词上,它在temp_word 中添加了垃圾字符, 我检查了gdbtemp_char 不包含垃圾,但是当strcat 运行时,附加到temp_word 的最新字符将类似于W\006

它将\006附加到第二个单词中的所有字符,

我在终端上看到的输出很好,但是打印出strcmp 并将resultexpected_result 相比较返回-94

  • 可能是什么问题?
  • \006 字符是什么?
  • 为什么strcat加了?
  • 如何防止这种行为?

【问题讨论】:

  • 请想想你分配len + 1字节的原因...为什么+1在那里?你使用你分配的额外字节吗?
  • 另外请想想你在reverseWord 中分配的内存会发生什么变化。何时何地免费?
  • @Someprogrammerdude 实际上我是 C 新手,感谢您指出我需要阅读更多内容,第一个,我不知道,第二个是我关心的问题之一,但是当然我不能free一个变量然后返回它
  • 考虑使用strtok 函数以及它如何防止内存泄漏。将strtok 的输出传递给您的反向单词函数,然后通过交换单词的元素直到到达它的末尾来执行就地反转。如何使用 strtok 的空终止 C 字符串输出来避免使用 malloc 占用 RAM?

标签: c string c-strings strcat


【解决方案1】:

strcat() 需要“C”字符串的第一个字符的地址,实际上是char-数组,其中至少有一个元素等于'\0'

内存temp_word指向和内存&amp;temp_char都不满足这样的要求。

因此,臭名昭著的未定义行为被调用,从那时起任何事情都可能发生。

一个可能的解决办法是改变

      temp_word = (char *) malloc (text_size + 1);

成为

      temp_word = malloc (text_size + 1); /* Not the issue but the cast is 
                                             just useless in C. */
      temp_word[0] = '\0';

还有这个

        strcat(temp_word, &temp_char);

成为

        strcat(temp_word, (char[2]){temp_char});

其余代码可能存在其他问题。

【讨论】:

  • 它确实有效,但我不明白如何,首先temp_word[0] = '\0',为什么我们在字符串的开头放置一个NULL指针?
  • 我的意思是空字符*
  • @DarkSuniuM:不是空指针,而是空字符。引用我的回答:""C"-strings, ... 实际上是至少一个元素等于 '\0' 的字符数组。"
【解决方案2】:

函数 strcat 处理字符串。

在这段代码中sn-p

  // assign and cast test[i+j] to temp_char as a character,
  // (it reads it as string by default)
  temp_char = (char) text[i+j];

  // concat temp_char to the temp_word
  strcat(temp_word, &temp_char); // <= PROBLEM

指针temp_word 和指针&amp;temp_char 都不指向字符串。

此外,数组output 不附加终止零字符,例如当源字符串由空格组成时。

在任何情况下,您的方法都过于复杂,并且有许多冗余代码,例如 for 循环中的条件和 if 语句中的条件相互重复。

  for(i = 0; i < len; i++) {

    //…

    // if the text[i] is NULL, just get out of the loop
    if (text[i] == '\0') {
      break;
    }

函数可以写得更简单,如下面的演示程序所示。

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

char * reverse_words( const char *s )
{
    char *result = malloc( strlen( s ) + 1 );

    if ( result != NULL )
    {
        char *p = result;

        while ( *s != '\0' )
        {
            while ( isblank( ( unsigned char )*s ) )
            {
                *p++ = *s++;
            }


            const char *q = s;

            while ( !isblank( ( unsigned char )*q ) && *q != '\0' ) ++q;

            for ( const char *tmp = q; tmp != s; )
            {
                *p++ = *--tmp;
            }

            s = q;
        }

        *p = '\0';
    }

    return result;
}

int main(void) 
{
    const char *s = "Hello World";

    char *result = reverse_words( s );

    puts( s );
    puts( result );

    free( result );

    return 0;
}

程序输出是

Hello World
olleH dlroW

【讨论】:

    【解决方案3】:

    垃圾字符的根本原因是您对 strcat 函数的第二个参数使用了错误的输入。请参阅下面的说明:

    在函数的开头声明:

      int i, j;
      size_t len = strlen(text);
      size_t text_size = len * sizeof(char);
      // output containst the output or the result
      char *output;
    
      // temp_word is a temporary variable,
      // it contains each word and it will be
      // empty after each space.
      char *temp_word;
    
      // temp_char is a temporary variable,
      // it contains the current character
      // within the for loop below.
      char temp_char;
    

    您可以在堆栈中打印变量的地址,它们将是这样的:

    printf("&temp_char=%p,&temp_word=%p,&output=%p,&text_size=%p\n", &temp_char, &temp_word,&output,&text_size);
    result:    
    &temp_char=0x7ffeea172a9f,&temp_word=0x7ffeea172aa0,&output=0x7ffeea172aa8,&text_size=0x7ffeea172ab0
    

    如你所见,&temp_char(0x7ffeea172a9f)在栈底,接下来的1个字节是&temp_word(0x7ffeea172aa0),接下来的8个字节是&output(0x7ffeea172aa8),以此类推(我用的是64位操作系统,所以需要8 个字节为一个指针)

     // concat temp_char to the temp_word
      strcat(temp_word, &temp_char); // <= PROBLEM
    

    请参阅此处的 strcat 描述:http://www.cplusplus.com/reference/cstring/strcat/

    strcat 第二个参数 = &temp_char = 0x7ffeea172a9f。 strcat 认为 &temp_char(0x7ffeea172a9f) 是源字符串的起点,而不是像你期望的那样只添加一个字符,它将把所有从 &temp_char(0x7ffeea172a9f) 开始的字符追加到 temp_word ,直到它遇到终止空字符强>

    【讨论】:

      猜你喜欢
      • 2021-11-05
      • 2016-03-14
      • 2016-03-03
      • 1970-01-01
      • 2021-11-13
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多