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

在C中复制字符串的一部分,c,string,C,String,这看起来应该很简单,但出于某种原因,我无法让它发挥作用。我有一个名为seq的字符串,如下所示: ala ile val 我想将前3个字符复制到另一个字符串中。我使用命令: memcpy(fileName, seq, 3 * sizeof(char)); 这应该是fileName=“ala”,对吗?但由于某种原因,我得到了fileName=“ala9”。我现在只是说fileName[4]='\0'来解决这个问题,但我想知道为什么我会得到9 注: 将seq改为 ala ile val ser

这看起来应该很简单,但出于某种原因,我无法让它发挥作用。我有一个名为seq的字符串,如下所示:

ala
ile
val
我想将前3个字符复制到另一个字符串中。我使用命令:

memcpy(fileName, seq, 3 * sizeof(char));
这应该是
fileName=“ala”
,对吗?但由于某种原因,我得到了
fileName=“ala9”
。我现在只是说
fileName[4]='\0'
来解决这个问题,但我想知道为什么我会得到9

注: 将seq改为

ala
ile
val
ser
然后重新运行相同的代码,文件名变成
“alaK”
。不再是9,但仍然是一个错误字符。

您需要设置

fileName[3] = 0;

确保文件名有足够的空间容纳字符串NUL字节的结尾。

您应该使用
文件名[3]='\0'。至于为什么有必要:因为没有其他东西为字符串设置NUL终止符,所以您必须这样做

编辑:当然,对于实际使用,您不会像上面所示那样使用常量。通常,您会使用以下内容:

char *substring(char *out, char const *in, size_t len) { 
    memcpy(out, in, len);
    out[len] = '\0';
    return out;
}
请注意,您使用
memcpy
的想法非常正确
strncpy
(举个明显的例子)并不是用于此(或几乎任何其他)目的的正确方法。在要避免的标准库函数列表中,
strncpy
排在第二位,仅次于
get
(不过,公平地说,我必须指出,
strtok
紧随其后)

还请注意(与大多数标准库函数一样),这不会尝试验证您传递的参数——例如,如果您让它将长度仅为10个字符的字符串中的99个字符复制到长度仅为5个字符的缓冲区中,它仍会尝试复制99个字符,从而产生未定义的行为)


Edit2:一种替代方法是。

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


编辑:wolfPack88有一个很好的观点。您确实需要更改文件名[3]。此外,下面的评论还提出了一些关于strncpy的要点,这也是一个值得学习的选择。

原因是您从seq复制了三个字符的字节,但是,没有终止空字符。因此,您的解决方案不是解决方案,而是正确的解决方案

C字符串应以null结尾。如果不是,则字符串的“用户”将一直读取,直到无法进一步读取为止,这将导致未定义的行为


顺便说一句,为什么不使用strncpy?

这个意外的字符是一个未正确地以null结尾的工件
文件名

在这种情况下,
fileName
必须是长度至少为4的
char
缓冲区(三个用于三个字符,一个用于终止空字符)。要设置空字符,可以使用:

fileName[3] = '\0';

memcpy

之后,除了null终止字符串之外

fileName[3] = '\0';

您可能还想考虑使用<代码> StncPy < /C> >而不是<代码> MycPy。另外,

sizeof(char)
的计算值应始终为1,因此它是冗余的


祝你好运

C中的字符串以nul结尾,这意味着您需要在字符串末尾使用nul字符。看起来你很幸运在下一个角色中有一个nul角色,所以你只多了一个垃圾角色,您还可以获得数千个垃圾字符…

sprintf是您的朋友,它可以从一个字符串的中间提取字符,并将它们放入以空结尾的字符缓冲区

sprintf(fileName, "%.3s", seq);

甚至

snprintf(fileName, sizeof(fileName), "%.*s", len, seq);

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

标准C语言库没有专门用于复制字符串部分的功能。正确的方法是使用
memcpy
(正如您已经做的那样),显式null终止结果。您忘记了终止结果,这就是为什么在复制的字符串部分之后会看到奇怪的额外字符

请注意,
memcpy
只有在您事先知道源字符串的长度时才起作用,即您知道字符串的复制部分完全位于源字符串内部。如果有一个机会,源的复制部分包含终止空字符(即源字符串在复制部分的中间结束),那么您必须要么编写自己的函数进行复制,要么使用非标准但广泛可用的<代码> StrcCPy < /C>
有时,您可能会遇到一些代码示例,它们试图为此目的使用
strncpy
函数。虽然在某些情况下它可能看起来“有效”,但考虑到它不打算这样使用,使用strncpy绝对没有意义。

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

在上次复制的字符后手动设置字符是正确的做法(当源字符不是完整的C字符串时)。为什么你认为这是一个“工作”?我想我的印象是,MimcPy会在我移动它之后为我终止字符串。哦,好吧。谢谢您的帮助。@wolfPack88:memcpy为什么要终止字符串?它不知道您在复制字符串(而不是结构、数组、int或其他任何内容)。Memcpy完全按照你说的做了。没别的了。如果您想要“感知”字符串,请使用strcpy和其他strXXX相关函数。@wolfPack88:
memcpy
对以空结尾的字符串一无所知。它只知道字节的范围。@wolfPa
snprintf(fileName, sizeof(fileName), "%.*s", len, seq);