Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-长度大于源字符串长度的带有char*的memcpy_C_String_Memcpy_Strcpy - Fatal编程技术网

C-长度大于源字符串长度的带有char*的memcpy

C-长度大于源字符串长度的带有char*的memcpy,c,string,memcpy,strcpy,C,String,Memcpy,Strcpy,我现在有以下C代码 int length = 50 char *target_str = (char*) malloc(length); char *source_str = read_string_from_somewhere() // read a string from somewhere // with length, say 20 memcpy(target_str, source_s

我现在有以下C代码

int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere() // read a string from somewhere
                                                //    with length, say 20
memcpy(target_str, source_str, length);
该场景是用50个字节初始化
target\u str
source_str
是一个长度为20的字符串

如果我想将
源\u str
复制到
目标\u str
中,我使用长度为50的memcpy(),长度为
目标\u str
。我在memcpy中使用
length
的原因是,
source_str
的最大值可以是
length
,但通常小于该值(在上面的示例中为20)

现在,如果我想根据其终止字符(
'\0'
)复制到
source\u str
的长度,即使memcpy长度大于终止字符的索引,上面的代码是正确的方法吗?还是有别的建议


感谢您的帮助。

memcpy用于复制固定内存块,因此如果您要复制由
'\n'
终止的较短内存块,您不想使用memcpy

还有其他函数,如strncpy或strlcpy,可以执行类似的操作。 最好检查实现的功能。为了可读性,我从原始源代码中删除了优化版本

这是memcpy实现的一个示例:

很明显,在这里,两段内存都被访问了n次。无论源字符串或目标字符串的大小如何,如果字符串较短,则会导致内存复制超过字符串。这是不好的,会导致各种不必要的行为

这是strlcpy,来自:

这里的技巧是
n&&(*d=0)
的计算结果为false,将打破循环条件并提前退出

因此,这给了你想要的行为

该场景是用50个字节初始化目标_str。source_str是长度为20的字符串

如果我想将源_str复制到目标_str,我会使用上面的memcpy(),长度为50,这是目标_str的大小

目前,您要求memcpy读取源字符串结尾后的30个字符,因为它不关心源上可能存在的空终止符,这是一种未定义的行为

因为复制字符串,所以可以使用strcpy而不是memcpy

但是大小的问题可以逆转,我的意思是目标可以比源小,如果没有保护,你将再次有一个未定义的行为

因此,您可以使用strncpy给出目标的长度,只要注意在目标小于源的情况下添加最终空字符的必要性:

int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere(); // length unknown

strncpy(target_str, source_str, length - 1); // -1 to let place for \0
target_str[length - 1] = 0; // force the presence of a null character at end in case
现在,如果我想根据源代码的终止字符('\0')复制源代码的长度,即使memcpy长度大于终止字符的索引,上面的代码是正确的方法吗

没有;您将复制
source\u str
的整个内容,即使它出现在为它所指向的字符串分配的空间结束之前,也会复制空终止符

如果您关心的是最小化程序使用的辅助空间,那么您可以使用
strlen
来确定
source\u str
的长度,并在此基础上分配
target\u str
。另外,
strcpy
memcpy
类似,但专门用于以null结尾的字符串(请注意,它没有“size”或“length”参数):

如果我想将源\u str复制到目标\u str,我会使用上面提到的memcpy() 长度为50,这是target_str的大小。我使用 memcpy中的长度是源字符串的最大值 长度,但通常小于该长度(在上面的示例中为20)

区分两者是至关重要的

  • source\u str
    指向的数组的大小,以及
  • source\u str
    指向的字符串长度(如果有)(+/-终止符)
如果
source\u str
确定指向长度大于等于50的数组,则您提供的
memcpy()
方法是正确的。如果不是,那么当
source\u str
实际上指向一个较短的数组时,它会产生未定义的行为。在C实现能力范围内的任何结果都可能发生

如果
source\u str
肯定指向长度不超过
length-1
个字符的(正确终止的)C字符串,并且如果要复制的是它的字符串值,那么
strcpy()
memcpy()
更自然。它将复制所有字符串内容,包括终止符。当
source\u str
指向长度小于
的数组时,只要该数组包含字符串终止符,就不会出现问题


如果这两种情况都不一定成立,那么你想做什么就不清楚了。
strncpy()
函数可以覆盖其中一些情况,但它不能覆盖所有情况。

为什么不
strlen(source_str)
,那么您可以分配确切的大小?另外,您不需要强制转换
malloc
的结果
size_t strlcpy(char *d, const char *s, size_t n)
{
    char *d0 = d;
    size_t *wd;

    if (!n--) goto finish;
    for (; n && (*d=*s); n--, s++, d++);
    *d = 0;
finish:
    return d-d0 + strlen(s);
}
int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere(); // length unknown

strncpy(target_str, source_str, length - 1); // -1 to let place for \0
target_str[length - 1] = 0; // force the presence of a null character at end in case
char *target_str = NULL;
char *source_str = read_string_from_somewhere();
size_t len = strlen(source_str);

target_str = malloc(len + 1);

strcpy(target_str, source_str);

// ...

free(target_str);
target_str = NULL;