strcat 将垃圾添加到字符串中
strcat adds junk to the string
我正在尝试颠倒句子,但不改变单词的顺序,
例如:"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] == '[=10=]') {
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] != '[=10=]')) {
// 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;
}
问题出在我用 <= PROBLEM
标记的行上,在本例中是 "Hello" 的第一个词,它做的一切都很好。
在本例中为 "World" 的第二个单词上,它向 temp_word
添加垃圾字符,
我用 gdb
检查了它,temp_char
不包含垃圾,但是当 strcat
运行时,附加到 temp_word
的最新字符类似于 W[=17= ]6
,
它将 [=18=]6
附加到第二个单词中的所有字符,
我在终端上看到的输出很好,但是打印出 strcmp
并将 result
与 expected_result
returns -94
分开。
- 可能是什么问题?
[=18=]6
字符是什么?
- 为什么
strcat
添加它?
- 如何防止这种行为?
strcat()
期望 "C"-字符串的第一个字符的地址,实际上是 char
-数组,至少有一个元素等于 '[=16=]'
。
内存temp_word
指向和内存&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] = '[=11=]';
还有这个
strcat(temp_word, &temp_char);
成为
strcat(temp_word, (char[2]){temp_char});
其余代码可能还有其他问题。
函数 strcat 处理字符串。
在此代码段中
// 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
和指针 &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] == '[=11=]') {
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 != '[=12=]' )
{
while ( isblank( ( unsigned char )*s ) )
{
*p++ = *s++;
}
const char *q = s;
while ( !isblank( ( unsigned char )*q ) && *q != '[=12=]' ) ++q;
for ( const char *tmp = q; tmp != s; )
{
*p++ = *--tmp;
}
s = q;
}
*p = '[=12=]';
}
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
垃圾字符的根本原因是您对 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位OS,所以一个指针需要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_word 所有从 &[ 开始的字符=28=](0x7ffeea172a9f) ,直到遇到终止空字符
我正在尝试颠倒句子,但不改变单词的顺序,
例如:"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] == '[=10=]') {
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] != '[=10=]')) {
// 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;
}
问题出在我用 <= PROBLEM
标记的行上,在本例中是 "Hello" 的第一个词,它做的一切都很好。
在本例中为 "World" 的第二个单词上,它向 temp_word
添加垃圾字符,
我用 gdb
检查了它,temp_char
不包含垃圾,但是当 strcat
运行时,附加到 temp_word
的最新字符类似于 W[=17= ]6
,
它将 [=18=]6
附加到第二个单词中的所有字符,
我在终端上看到的输出很好,但是打印出 strcmp
并将 result
与 expected_result
returns -94
分开。
- 可能是什么问题?
[=18=]6
字符是什么?- 为什么
strcat
添加它? - 如何防止这种行为?
strcat()
期望 "C"-字符串的第一个字符的地址,实际上是 char
-数组,至少有一个元素等于 '[=16=]'
。
内存temp_word
指向和内存&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] = '[=11=]';
还有这个
strcat(temp_word, &temp_char);
成为
strcat(temp_word, (char[2]){temp_char});
其余代码可能还有其他问题。
函数 strcat 处理字符串。
在此代码段中
// 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
和指针 &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] == '[=11=]') {
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 != '[=12=]' )
{
while ( isblank( ( unsigned char )*s ) )
{
*p++ = *s++;
}
const char *q = s;
while ( !isblank( ( unsigned char )*q ) && *q != '[=12=]' ) ++q;
for ( const char *tmp = q; tmp != s; )
{
*p++ = *--tmp;
}
s = q;
}
*p = '[=12=]';
}
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
垃圾字符的根本原因是您对 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位OS,所以一个指针需要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_word 所有从 &[ 开始的字符=28=](0x7ffeea172a9f) ,直到遇到终止空字符