【问题标题】:Memset and charactersMemset 和字符
【发布时间】:2016-11-23 17:50:21
【问题描述】:

我的目标是将source 字符串复制到dest 字符串。如果我编译以下程序:

#include <stdio.h>

int main(void) {
    char dest[6];
    char source[6];
    
    strcpy(dest,source);
    
    while (*dest) { printf("%c",*dest++); }
    while (*source) {printf("%c",*source++); }
    
    return 0;
}

我收到运行时错误。我怀疑这是因为strcpy 从源复制到目标,直到遇到\0。但是,它没有遇到空字符并继续从缓冲区复制,直到发生运行时错误。为了解决这个问题,我修改了代码如下:

#include <stdio.h>

int main(void) {
    char dest[6];
    char source[6];
    
    
    memset(dest, '\0', 6*sizeof(dest)); //trying to set dest to '/0'
    strcpy(dest,source);
    
    while (*dest) { printf("%c",*dest++); }
    while (*source) {printf("%c",*source++); }
    
    return 0;
}

我收到以下错误:

prog.c:11:38: 错误:需要左值作为增量操作数

 while (*dest) { printf("%c",*dest++); }
                                  ^

prog.c:11:38: 错误:需要左值作为增量操作数

 while (*dest) { printf("%c",*source++); }
                                    ^

为什么会这样?

【问题讨论】:

  • 第一个程序 doesn't compile 与第二个程序没有相同的原因。你确定那是你使用的来源吗?
  • 另外,您不能将 ++ 应用于数组。 :-)
  • 如果dest 是一个数组,dest++ 不是合法的 C 代码。
  • "我的目标是将目标字符串复制到源字符串。"我猜你的意思正好相反。
  • 这一行:memset(dest, '\0', 6*sizeof(dest)); 正在设置 36 个字节。前 6 个字节之后的所有字节都超出了数组的末尾。这是未定义的行为,可能导致段错误事件。

标签: c arrays string memset


【解决方案1】:

对于初学者,如果您要使用标准 C 函数 strcpy 将其复制到另一个字符数组中,则源数组应为零终止。所以代替这种说法

memset(dest, '\0', 6*sizeof(dest)); 

你至少应该写

memset(source, '\0', 6*sizeof(source));
       ^^^^^^                ^^^^^^^

但是,即使这个语句也是错误的,因为它会覆盖为数组分配的内存。 sizeof( source ) 已经等于 6 个字节,因为它来自数组声明

char source[6];

所以你必须写

memset(source, '\0', sizeof(source));
                     ^^^^^^^^^^^^^

其实写两句就够了

char source[6] = { '\0' };

或喜欢

char source[6] = "";

或喜欢

char source[6];
source[0] = '\0';

数组是不可修改的左值。因此,您可能不会写例如以下方式

while (*dest) { printf("%c",*dest++); }

你可以用这个语句代替

for ( char *p = dest; *p; ++p ) { printf("%c", *p); }

考虑到不会输出任何内容,因为数组包含一个空字符串。您可以使用一些非空字符串文字初始化源数组。

【讨论】:

  • 这一行:memset(source, '\0', 6*sizeof(source)); 不正确。 sizeof(source) 是 6,6*6 是 36,所以这将清除 36 个字节,前 6 个字节超出数组边界的末尾。结果是未定义的行为,并可能导致段错误事件。建议删除6*
  • @user3629249 你在写评论之前阅读了整篇文章吗?:)
  • 是的,我确实阅读了整篇文章和您的回答。您的答案是传播 OP 发布的代码存在的问题之一。
  • @user3629249 很抱歉,但与我的回答相比,您的所有这些 cmets 都没有意义。
  • 您的答案中的第一件事是使用:memset(source, '\0', 6*sizeof(source));,它将清除 36 个字节到 '\0',这将超出源缓冲区,它只有 6 个字节长
【解决方案2】:

以下代码干净地编译,并执行所需的操作。

对贴出的代码与this的不同之处进行了注释。

#include <stdio.h>  // printf()
#include <string.h> // strcpy()

int main(void) 
{
    char dest[6];  // declared, containing garbage
    char source[6] = "12345"; // declared, containing the string "12345\0"

    strcpy(dest,source); 
    // now both arrays contain the string "12345\0"

    // best to use a 'for()' statement for indexing through an array
    for( size_t i=0; dest[i];   i++ )  { printf("%c", dest[i]);  }
    printf( "\n" );  // output the buffered data to the terminal
    for( size_t i=0; source[i]; i++ )  { printf("%c", source[i]);}
    printf( "\n" );  // output the buffered data to the terminal

    // note, the following lines contain a precedence problem in
    // the increment expressions and 
    // the address of an array declaration cannot be incremented
    //while (*dest) { printf("%c",*dest++); }
    //while (*source) {printf("%c",*source++); }

    //return 0;// with modern C compilers, 
             // this line is not necessary in a 'main()' function
             // when returning 0
} // end function: main

【讨论】:

    【解决方案3】:

    strcpy 不是安全函数,建议使用strncpy

    错误是由于您尝试递增数组,这是一个右值(即一个常量,您不能将它放在符号= 的左侧)。

    遍历数组的常用方法是使用如下指针:

    char *p = dest;
    while (*p) { printf("%c",*p++); }
    

    【讨论】:

    • 想解释一下反对意见吗?
    • 我没有投反对票,但strncpy 不仅仅是strcpy 的更安全版本。由于历史原因,它实际上做了一些非常令人惊讶的事情,因此在许多情况下它可能不是您想要的。
    • 据我记得 strncpy 的缺点是,如果达到最大大小,它不会添加 '\0' 字节,但这不是问题,因为他使用的是未初始化的数据,在我看来只是试图操纵指针和内存。
    • 如果源字符串太短,它也会填充目标缓冲区。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2021-01-20
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    相关资源
    最近更新 更多