memcpy之后printf的奇怪行为

时间:2016-03-20 01:08:43

标签: c printf memcpy

我在C中打印字符串时遇到问题(好吧,*ptr指向的字符串。)

我有以下代码:

char *removeColon(char *word) {
    size_t wordLength;
    char word1[MAXLENGTH];

    wordLength = strlen(word);
    wordLength--;
    memcpy(word1, word, wordLength);
    printf("word1: %s\n", word1);
    return *word1;
}

我用word = "MAIN:"运行它(word的值来自strtok从文件读取的字符串)。 它工作正常,直到printf,结果是:

字1:MAIN╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠

然后有一个例外,一切都会中断。

有什么想法吗?

4 个答案:

答案 0 :(得分:1)

您必须确保(1)每个字符串都是以空字符结尾的,并且(2)您没有尝试修改字符串文字。你有很多方法可以采取。使用strlen删除最后一个字符(任何字符)的简单方法:

char *rmlast (char *s)
{
    if (!*s) return s;      /* return if empty-string */
    s[strlen (s) - 1] = 0;  /* overwrite last w/nul   */
    return s;
}

(您还可以使用string.h函数strchr(搜索0),strrchr(搜索目标字符,如果通过),{{1} (搜索几个字符中的一个)等,以便找到最后一个字符)

或者你可以用指针做同样的事情:

strpbrk

如果要将删除限制为任何特定字符,并且在使用 nul-terminatedating 字符覆盖它之前在函数中进行简单比较,也可以传递最后一个感兴趣的字符。

查看两者并告诉我您是否有任何疑问。

答案 1 :(得分:1)

您的函数removeColon应该

  • 就地操作并修改作为参数传递的字符串
  • 被赋予目标缓冲区并将缩短的字符串复制到它或
  • 为缩短的字符串分配内存并返回该内容。

只将字符复制到本地数组,而不是空终止符,也不在缓冲区中设置一个,将此数组传递给printf("%s", ...)调用未定义的行为:printf继续打印缓冲区内容直到它找到一个'\0'字节,它甚至超出了数组的末尾,调用未定义的行为,打印垃圾并最终在崩溃中死亡。

您无法返回指向自动数组的指针,因为该函数一返回就会变为不可用。稍后取消引用指针将调用未定义的行为。

这是一个适用的功能:

char *removeColon(char *word) {
    if (*word) word[strlen(word) - 1] = '\0';
    return word;
}

这是复制到目标缓冲区的一个,假设足够长:

char *removeColon(char *dest, const char *word) {
    size_t len = strlen(word);
    memcpy(dest, word, len - 1);
    dest[len - 1] = '\0';
    return dest;
}

这是一个分配内存的方法:

char *removeColon(const char *word) {
    size_t len = strlen(word);
    char *dest = malloc(len);
    memcpy(dest, word, len - 1);
    dest[len - 1] = '\0';
    return dest;
}

答案 2 :(得分:0)

wordLength = strlen(word);

您必须在长度中包含空终止符,因为每个字符串都有一个终止字符,其ASCII值为0,在C中拼写为\0。另外,使用str...系列函数代替mem...,因为前者用于空终止字符串,后者用于数组。此外,您无法返回本地堆栈分配的数组。根据函数的代码,听起来你正在删除最后一个字符。如果是这种情况,最好做

void remlast(char *str)
{
    str[strlen(str) - 1] = '\0';
}

请注意,这不适用于空字符串。

答案 3 :(得分:0)

您复制wordLength个字节,但无法添加空终止字节。由于word1在此副本之前未初始化,因此其余字节未定义。

因此,当printf尝试打印字符串时,它找不到空终止符并继续读取,直到它在数组边界之外的某处找到空字节。这是未定义的行为。

复制字节后,需要手动添加空终止符:

memcpy(word1, word, wordLength);
word1[wordLength] = '\0';

此外,您将返回指向局部变量的指针。当函数返回时,该变量超出范围,并且取消引用该指针也是未定义的行为。

不是让word1成为本地数组,而是可以为它动态分配内存:

char *word1 = malloc(strlen(word));

如果你这样做,你需要在调用函数的某个地方free这个内存。另一个选择是让调用者传入适当大小的缓冲区:

void removeColon(char *word, char *word1) {