C语言的新特性; strcat具有意想不到的结果

j1dl9f46  于 5个月前  发布在  其他
关注(0)|答案(2)|浏览(64)

我正在将一个脚本从Bash转换为C。我是C的新手。有很多东西需要我学习。我有代码,我有调试。一个变量的printf与从substr构建的内容输出意外的结果。
作为一个学习概念:

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

int main() {
    char one[5] = "abcde";
    char two[3] = "fgh";
    char three[8] = "ijklmnop";

    int size = strlen( one ) + strlen( two ) + strlen( three );
    char str[ size ];

    strcpy( str, one );
    strcat( str, "_" );
    strcat( str, two );
    strcat( str, "_" );
    strcat( str, three);

    printf( "string is: %s\n", str );
    return 0;
}

字符串
我得到的结果如下:

string is: nop abcdefghijklmnopabd


很明显,内存没有得到适当的管理,我很困惑,因为上面的例子看起来像是一个很好的函数教科书用例。
我尝试了许多调试技术;然而,这是我用过的最低层的堆栈语言。

oymdgrw7

oymdgrw71#

你有未定义的行为,因为你的数组没有为null终止符留下空间。

char one[5] = "abcde";

字符串
这不是有效的C字符串。以下是:

char one[6] = "abcde";


或者让编译器计算出数组需要多大:

char one[] = "abcde";


完成后,您需要使str足够大,以容纳空终止符和两个'_'字符。虽然在这种情况下不太可能有任何实际影响,但将size输入为size_tint更正确。

size_t size = strlen( one ) + strlen( two ) + strlen( three );
char str[ size + 3 ];


由于您没有修改onetwothree,因此可能只是将它们声明为指向字符串的指针。

const char *one = "abcde";
const char *two = "fgh";
const char *three = "ijklmnop";

5cnsuln7

5cnsuln72#

让编译器为您计数:
char one[5] = "abcde"; -> char one[] = "abcde";
或者更好的是:const char *one = "abcde";,如果你不需要修改这些字符串。
strcpystrcat容易发生缓冲区溢出,请考虑使用snprintfsnprintf的一个优点是(在malloc的帮助下)您不需要硬编码最终大小(在您的情况下为size + 3

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

int main(void)
{
    const char *one = "abcde";
    const char *two = "fgh";
    const char *three = "ijklmnop";
    const char *fmt = "%s_%s_%s";
    size_t size = 1 + (size_t)snprintf(NULL, 0, fmt, one, two, three);
    char *str = malloc(size);

    if (str != NULL)
    {
        snprintf(str, size, fmt, one, two, three);
        printf("string is: %s\n", str);
        free(str);
    }
    return 0;
}

字符串
当然,你可以像在你的代码片段中那样使用char str[size];,但我个人更喜欢避免使用VLA。

相关问题