在C中复制字符串的一部分

wol*_*k88 6 c string

这似乎应该非常简单,但出于某种原因,我没有让它工作.我有一个名为seq的字符串,如下所示:

ala
ile
val
Run Code Online (Sandbox Code Playgroud)

我想取前3个字符并将它们复制到不同的字符串中.我使用命令:

memcpy(fileName, seq, 3 * sizeof(char));
Run Code Online (Sandbox Code Playgroud)

这应该是fileName = "ala",对吧?但出于某种原因,我明白了fileName = "ala9".我正在解决这个问题fileName[4] = '\0',但我想知道为什么我会得到那个9.

注意:将seq更改为

ala
ile
val
ser
Run Code Online (Sandbox Code Playgroud)

并重新运行相同的代码,fileName成为"alaK".不再是9,但仍然是一个错误的角色.

Pac*_*ace 18

C使用空终止符来表示字符串的结尾.memcpy不知道你是在复制字符串(它只是复制字节),所以它不会想要放一个字符串.您的解决方法实际上是正确的答案.

编辑:wolfPack88有一个好点.你真的需要改变文件名[3].此外,下面的评论提出了一些关于strncpy的好点,这也是一个值得学习的选择.

  • @Bruno:不,不是.事实上,关于唯一一次`strncpy`是正确的答案是关于要避免的功能的问题. (4认同)
  • @Bruno:因为`strncpy`被指定做一些很少用的东西.如果您的源短于指定的源,则会将结果填充到指定的大小.如果源的长度超过指定的值,则结果中不包含NUL终止符.它可以正常工作(将字符串转换为UNIX文件名),但这就是全部. (2认同)

Chr*_*odd 11

sprintf是你的朋友,用于从一个字符串的中间提取字符并将它们放在具有空终止的字符缓冲区中.

sprintf(fileName, "%.3s", seq);
Run Code Online (Sandbox Code Playgroud)

要么

sprintf(fileName, "%.*s", 3, seq);
Run Code Online (Sandbox Code Playgroud)

甚至

snprintf(fileName, sizeof(fileName), "%.*s", len, seq);
Run Code Online (Sandbox Code Playgroud)

会给你你想要的.该*版本允许可变长度,并且snprintf更安全,以避免缓冲区溢出


flo*_*rin 5

你需要设置

fileName[3] = 0;
Run Code Online (Sandbox Code Playgroud)

确保fileName有足够的空间用于字符串NUL字节的结尾.


Jer*_*fin 5

你应该使用filename[3]='\0';.至于为什么有必要:因为没有别的东西为字符串设置了NUL终止符,所以你必须这样做.

编辑:当然,对于实际使用,你不要使用像我上面所示的常量.通常你会使用类似的东西:

char *substring(char *out, char const *in, size_t len) { 
    memcpy(out, in, len);
    out[len] = '\0';
    return out;
}
Run Code Online (Sandbox Code Playgroud)

请注意,尽管你确实使用了很多正确的想法memcpy.strncpy(对于一个明显的例子)并不是真正适合这个(或几乎任何其他)目的的东西.在要避免的标准库函数strncpy列表中,列表中排在第二位,仅排在后面gets(但是,公平地说,我必须指出它strtok紧随其后的第三位).

另请注意(与大多数标准库函数一样),这不会尝试验证您传递的参数 - 例如,如果您告诉它将一个只有10个字符长的字符串中的99个字符复制到一个只有5个字符长的缓冲区中,它会尝试复制99个字符,产生未定义的行为).

Edit2:另一种方法是使用sprintf.


小智 5

如果要使用memcpy复制字符串,则必须在字符串的最后一个字符后手动设置字符"\ 0".如果您不想手动处理'\ 0',请改用strcpy或strncpy.

  • 注意:如果源字符串太长,strncpy()不保证空终止. (4认同)