我目前正在研究许多strcpy'和calloc的。然后我听说使用strncpy比较安全。所以我所做的是创建一个处理strcpy的函数。如下所示。
void safeStrncpy(char * dest, char * src){
//copy string
if(sizeof(dest) >= strlen(src) + 1){
strncpy(dest, src, strlen(src));
}else{
if(realloc(dest, (strlen(src)) + 1) == NULL){
printf("error");
}else{
strncpy(dest, src, strlen(src));
}
}
}
您会注意到我使用了sizeof(dest)
。我真正想要用的部分是获取分配给dest
的内存大小,以便我知道何时使用realloc
。但后来我了解到你无法获得分配给dest的内存大小,所以我想到了一个解决方法。
char * l = calloc(10,sizeof(char));
printf("%s", strcpy(l,"asdfghjkldfghasdfghjkl"));
上面显示的代码将10个项目分配给指针l
。我认为如果我这样做并复制了比分配的更多的字符,它只会复制适合大小的字符。
我期待l的价值是" asdfghjkld"。但令我惊讶的是,它并没有。它复制了整个字符串,这是" asdfghjkldfghasdfghjkl"。
现在,为什么要使用calloc才会被覆盖?在char指针声明,内存分配和strcpy期间在后台发生了什么? c会自动重新分配内存吗?我是否需要担心这种行为,可能是安全问题?
答案 0 :(得分:1)
你问:
为什么strcpy会将更多字符复制到变量中?
将source指向的C字符串复制到destination指向的数组中,包括终止空字符(并在该点停止)。
为避免溢出,目标指向的数组大小应足够长,以包含与源相同的C字符串(包括终止空字符),并且不应在内存中与源重叠。
如果目标的长度不足以包含源,则不会指定程序的行为方式。最有可能的是,您的实现只是写入超出范围的内存,这将导致未定义的行为。
这是一个可能的解决方案。
创建一个struct
,其中包含char*
和一个大小。
typedef struct _MyString
{
char* data;
size_t size;
} MyString;
在safeStrncpy
void safeStrncpy(MyString* dest, char * src){
if(dest->size < strlen(src) + 1){
dest->size = strlen(src)+1;
dest->data = realloc(dest->data, dest->size);
}
strcpy(dest->data, src);
}
答案 1 :(得分:0)
您展示的代码误用strncpy()
。它也误用了sizeof()
。如果通过打印消息报告错误,则应将错误打印为标准错误,即stderr
(而不是标准输出)。最后,如果重新分配内存,调用代码不会知道这一点,这会导致realloc()
在内存中移动数据时出现问题。目前的代码是:
void safeStrncpy(char * dest, char * src){
//copy string
if(sizeof(dest) >= strlen(src) + 1){
strncpy(dest, src, strlen(src));
}else{
if(realloc(dest, (strlen(src)) + 1) == NULL){
printf("error");
}else{
strncpy(dest, src, strlen(src));
}
}
}
sizeof(dest)
是指针的大小(可能是4或8个字节)。您必须知道目标字符串的大小,因此您需要将其作为参数传递。strncpy(dest, src, strlen(src))
保证字符串不以空值终止。它告诉strncpy()
只复制与字符串中一样多的非空字符。我建议:
void safeStrncpy(char **p_buffer, size_t *p_bufsiz, const char *src)
{
size_t newlen = strlen(src) + 1;
if (*p_bufsiz < newlen)
{
char *n_buffer = malloc(newlen);
if (n_buffer == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", newlen);
return;
}
*p_buffer = n_buffer;
*p_bufsiz = newlen;
}
memmove(*p_buffer, src, newlen);
}
因为我确切地知道字符串有多长,所以不需要使用strcpy()
,它必须检查每个字符以查看它是否为空;使用memmove()
- 或memcpy()
如果您愿意,因为这次是安全的 - 可能会更快。
示例调用序列:
char *buffer = 0;
size_t bufsiz = 0;
char line[4096];
while (fgets(line, sizeof(line), stdin) != 0)
{
safeStrncpy(&buffer, &bufsiz, line);
…use buffer (which is of size bufsiz)…
}
free(buffer); // All done
请注意,您应该记录*p_buffer
和src
一定不能重叠。