如何覆盖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,而不是字符串的长度。如果目标缓冲区不够大,这也会产生未定义的行为。请改用 strlen
。 sizeof(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 类型上,在其他类型上你需要做更多。
例如,我有一个字符串。我只想更改字符串的开头几个字符,其余的保持原样。在 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,而不是字符串的长度。如果目标缓冲区不够大,这也会产生未定义的行为。请改用 strlen
。 sizeof(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 类型上,在其他类型上你需要做更多。