如何覆盖C中的字符串的一部分?

How to overwrite part of a string in C?

例如,我有一个字符串。我只想更改字符串的开头几个字符,其余的保持原样。在 C 中执行此操作的最佳方法是什么?

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

int main() {
    char src[40];
    char src2[40];
    char dest[12];

    memset(dest, '[=10=]', sizeof(dest));
    strcpy(src, "This is a string");
    strcpy(src2, "That");
    strncpy(dest, src, sizeof(src));
    strncpy(dest, src2, sizeof(src2));

    printf("Final copied string : %s\n", dest);
}

我希望将字符串从 "This is a string" 更改为 "That is a string"

有没有我缺少的简单方法来完成此操作?

sizeof(src2)40(它是整个数组的大小)——你可能是说 strlen(src2)(这只是字符串使用的字符数):

strncpy(dest, src2, strlen(src2));

请注意,您的代码存在缓冲区溢出问题:dest 数组不够大,无法容纳生成的字符串。它至少需要 17 个字符才能容纳 "This is a string" 字符串。您还需要使用 :

strncpy(dest, src, strlen(src));

这里有一些问题。

首先,dest只有12个字节长,短到装不下"This is a string"。尝试将该字符串复制到 dest 将溢出缓冲区。这会调用 undefined behavior。使其至少为 20 个字节。

第二个sizeof(src)给出了整个数组的大小,即40,而不是字符串的长度。如果目标缓冲区不够大,这也会产生未定义的行为。请改用 strlensizeof(src2).

也是如此

通过这些更改,您应该拥有:

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

int main() {
    char src[40];
    char src2[40];
    char dest[20];

    memset(dest, '[=10=]', sizeof(dest));
    strcpy(src, "This is a string");
    strcpy(src2, "That");
    strncpy(dest, src, strlen(src));
    strncpy(dest, src2, strlen(src2));

    printf("Final copied string : %s\n", dest);
}

我对 memset() 电话感到困惑和有点担心。 memset 调用允许使用 strncpy() 而不必担心终止 '\0'。这样的调用假定此逻辑将用于将从更高级别函数调用的通用函数中。

如果不是这种情况,那么第一个 strncpy() 应该替换为 strcpy 并且 memset 应该被放弃:

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

int main() {
    char src[40];
    char src2[40];
    char dest[20];

    /* memset(dest, '[=10=]', sizeof(dest)); -- No need for this */
    strcpy(src, "This is a string");
    strcpy(src2, "That");
    strcpy(dest, src, strlen(src)); /* strcpy will put a '[=10=]' at the end */
    strncpy(dest, src2, strlen(src2));

    printf("Final copied string : %s\n", dest);
}

但是,如果这将从更高级别的函数调用,那么我们确实需要检查传入字符串的长度 and/or malloc dest 缓冲区并释放它。 memset() 是房间里的大象,它表明还有更多的逻辑需要考虑。否则,只需将第一个 strncpy() 替换为 strcpy()。

扩展@dbush 的回答:

我认为代码仍然很脆弱。

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

int main() {
    char src[40];
    char src2[40];
    char dest[20];

这里创建了第一个陷阱:dest 小于两个源。虽然可以处理,但需要在后续代码中更加努力。最好使目标始终足够大以容纳源。

memset(dest, '[=11=]', sizeof(dest)); //Good

但是,将其他数组也初始化为 0 也是一个好主意。

memset(src, '[=12=]', sizeof(src));
memset(src2, '[=12=]', sizeof(src2));

旁注:当然,您可以通过使用数组初始化语法来省去 memset 的麻烦:

    char src[40] = {0};
    char src2[40] = {0};
    char dest[20] = {0};

如果 IRL 这两个字符串可能不是字符串常量,则接下来的两行可能存在危险。 (即使那样!)不提供长度检查......更好:

//    strcpy(src, "This is a string");
//    strcpy(src2, "That");

strncpy(src, "This is a string", sizeof(src)- 1);
strncpy(src2, "That", sizeof(src2) -1);

这样我们就可以确保不会造成任何溢出。 我们还确保 src 和 src2 中的字符串正确地以 null 结尾。

现在,将 src/src2 复制到 dest 也是危险的。一定要保证不溢出dest.

//strncpy(dest, src, strlen(src));
//strncpy(dest, src2, strlen(src2));

更好:

strncpy(dest, src, sizeof(dest) - 1);
strncpy(dest, "That is a long rubbish string that easily could overflow dest", sizeof(dest) -1);

我们只复制 dest 可以容纳并保留空终止符的数量。

现在开始替换前 X 个字符。同样,我们必须确保不会发生溢出。我们使用 strlen 来确定 src2 中以 null 结尾的字符串的实际大小,但需要 use/evaluate dest 的最大大小。因此 strlen 和 sizeof.

的混合

memcpy 只是为了好玩。您也可以使用 strncpy。

memcpy(dest, src2, strlen(src2) < sizeof(dest) ? strlen(src2) : sizeof(dest));

printf("Final copied string : %s\n", dest);

}

因此,整个安全实施如下所示:

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

int main() {
    char src[40] = {0};
    char src2[40] = {0};
    char dest[20] = {0};


    strncpy(src, "This is a string", sizeof(src)- 1);

    strncpy(src2, "That is a long rubbish string and sooooooooooooooooooooooooo much more", sizeof(src2) -1);

    strncpy(dest, src, sizeof(dest) - 1);

    memcpy(dest, src2, strlen(src2) < sizeof(dest) ? strlen(src2) : sizeof(dest));

    printf("Final copied string : %s\n", dest);
}

请注意sizeof的使用只是表面上等同于strlen;在有效的 char 类型上,在其他类型上你需要做更多。