在 C 中使用 strcat 进行动态字符串连接
Dynamic string concatenation with strcat in C
我在使用 strcat 时遇到问题,但是使用 realloc,strcat 会覆盖目标字符串
char *splitStr(char *line) {
char *str_;
str_ = (char *) malloc(1);
char *ptr = strtok(line,"\n");
int a;
while (ptr != NULL) {
if (ptr[0] != '$') {
printf("oncesi %s\n", str_);
a = strlen(ptr) + strlen(str_) + 1;
str_ = realloc(str_, a);
strcat(str_, ptr);
str_[a] = '[=10=]';
printf("sontasi:%s\n", str_);
}
ptr = strtok(NULL, "\n");
}
printf("splitStr %d\n", strlen(str_));
printf("%s", str_);
return str_;
}
我的输入值为 ;
*4
200
4814
SUCCESS
3204
所以我想通过strtok拆分这个输入值;
strtok(行,'\n');
并将所有不以“$”开头的字符连接到新字符。但是,此代码给出以下输出;
line: *4
oncesi
sontasi:*4
oncesi *4
200tasi:*4
200esi *4
4814asi:*4
4814si *4
SUCCESS:*4
SUCCESS*4
3204ESS:*4
splitStr 25
似乎覆盖了源字符串。
你知道为什么会发生这个问题吗?
以下建议代码:
- 干净地编译
- 执行指示的功能
- 为了输出的可读性稍作修改
- 检查来自
malloc()
和 realloc()
的错误
- 显示如何初始化 str[] 数组,这是 OP 发布代码中的问题。
- 函数:
strlen()
returns 一个 size_t
,而不是一个 int
。所以正确的输出格式转换说明符是:%zu
- 不在变量名上使用尾随下划线
现在,建议的代码:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char *splitStr( char *line )
{
printf("original line: %s\n", line);
char *str = malloc(1);
if( !str )
{
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
str[0] = '[=10=]'; // critical statement
char *token = strtok(line,"\n");
while( token )
{
if( token[0] != '$')
{
char* temp = realloc( str, strlen( token ) + strlen( str ) + 1 );
if( ! temp )
{
perror( "realloc failed" );
free( str );
exit( EXIT_FAILURE );
}
str = temp; // update pointer
strcat(str, token);
printf( "concat result: %s\n", str );
}
token = strtok(NULL, "\n");
}
printf("splitStr %zu\n", strlen(str));
return str;
}
int main( void )
{
char firstStr[] = "$abcd\n$defg\nhijk\n";
char *firstNewStr = splitStr( firstStr );
printf( "returned: %s\n\n\n\n", firstNewStr );
free( firstNewStr );
char secondStr[] = "abcd\ndefg\nhijk\n";
char *secondNewStr = splitStr( secondStr );
printf( "returned: %s\n\n\n\n", secondNewStr );
free( secondNewStr );
}
a 运行 提议的代码导致:
original line: $abcd
$defg
hijk
concat result: hijk
splitStr 4
returned: hijk
original line: abcd
defg
hijk
concat result: abcd
concat result: abcddefg
concat result: abcddefghijk
splitStr 12
returned: abcddefghijk
您的输入包含 Windows/DOS 行尾编码 "\r\n"
。
由于 strtok()
只是将 '\n'
替换为 '[=13=]'
,因此 '\r'
保留在字符串中。在输出时,它会将光标移动到左侧,并且额外的字符会覆盖旧字符,至少在视觉上是这样。
但是,您的连接字符串应该没问题。计算字符数,不要忘记为每一行包含一个 '\r'
:"*4\r200\r4814\rSUCCESS\r3204\r"
是 25 个字符,如输出 splitStr 25
所示。
补充说明:
- 正如其他人已经说过的那样,
str_ = (char *) malloc(1);
不会 初始化 space str_
指向。您需要自己执行此操作,例如 str_[0] = '[=20=]';
.
- 不要那样使用下划线。
- 您不需要转换
malloc()
的结果,它是与 char*
(和任何其他)兼容的 void*
。
我在使用 strcat 时遇到问题,但是使用 realloc,strcat 会覆盖目标字符串
char *splitStr(char *line) {
char *str_;
str_ = (char *) malloc(1);
char *ptr = strtok(line,"\n");
int a;
while (ptr != NULL) {
if (ptr[0] != '$') {
printf("oncesi %s\n", str_);
a = strlen(ptr) + strlen(str_) + 1;
str_ = realloc(str_, a);
strcat(str_, ptr);
str_[a] = '[=10=]';
printf("sontasi:%s\n", str_);
}
ptr = strtok(NULL, "\n");
}
printf("splitStr %d\n", strlen(str_));
printf("%s", str_);
return str_;
}
我的输入值为 ;
*4
200
4814
SUCCESS
3204
所以我想通过strtok拆分这个输入值; strtok(行,'\n');
并将所有不以“$”开头的字符连接到新字符。但是,此代码给出以下输出;
line: *4
oncesi
sontasi:*4
oncesi *4
200tasi:*4
200esi *4
4814asi:*4
4814si *4
SUCCESS:*4
SUCCESS*4
3204ESS:*4
splitStr 25
似乎覆盖了源字符串。 你知道为什么会发生这个问题吗?
以下建议代码:
- 干净地编译
- 执行指示的功能
- 为了输出的可读性稍作修改
- 检查来自
malloc()
和realloc()
的错误
- 显示如何初始化 str[] 数组,这是 OP 发布代码中的问题。
- 函数:
strlen()
returns 一个size_t
,而不是一个int
。所以正确的输出格式转换说明符是:%zu
- 不在变量名上使用尾随下划线
现在,建议的代码:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char *splitStr( char *line )
{
printf("original line: %s\n", line);
char *str = malloc(1);
if( !str )
{
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
str[0] = '[=10=]'; // critical statement
char *token = strtok(line,"\n");
while( token )
{
if( token[0] != '$')
{
char* temp = realloc( str, strlen( token ) + strlen( str ) + 1 );
if( ! temp )
{
perror( "realloc failed" );
free( str );
exit( EXIT_FAILURE );
}
str = temp; // update pointer
strcat(str, token);
printf( "concat result: %s\n", str );
}
token = strtok(NULL, "\n");
}
printf("splitStr %zu\n", strlen(str));
return str;
}
int main( void )
{
char firstStr[] = "$abcd\n$defg\nhijk\n";
char *firstNewStr = splitStr( firstStr );
printf( "returned: %s\n\n\n\n", firstNewStr );
free( firstNewStr );
char secondStr[] = "abcd\ndefg\nhijk\n";
char *secondNewStr = splitStr( secondStr );
printf( "returned: %s\n\n\n\n", secondNewStr );
free( secondNewStr );
}
a 运行 提议的代码导致:
original line: $abcd
$defg
hijk
concat result: hijk
splitStr 4
returned: hijk
original line: abcd
defg
hijk
concat result: abcd
concat result: abcddefg
concat result: abcddefghijk
splitStr 12
returned: abcddefghijk
您的输入包含 Windows/DOS 行尾编码 "\r\n"
。
由于 strtok()
只是将 '\n'
替换为 '[=13=]'
,因此 '\r'
保留在字符串中。在输出时,它会将光标移动到左侧,并且额外的字符会覆盖旧字符,至少在视觉上是这样。
但是,您的连接字符串应该没问题。计算字符数,不要忘记为每一行包含一个 '\r'
:"*4\r200\r4814\rSUCCESS\r3204\r"
是 25 个字符,如输出 splitStr 25
所示。
补充说明:
- 正如其他人已经说过的那样,
str_ = (char *) malloc(1);
不会 初始化 spacestr_
指向。您需要自己执行此操作,例如str_[0] = '[=20=]';
. - 不要那样使用下划线。
- 您不需要转换
malloc()
的结果,它是与char*
(和任何其他)兼容的void*
。