【问题标题】:Structure field overwritten when using memcpy使用 memcpy 时结构字段被覆盖
【发布时间】:2014-07-14 14:08:04
【问题描述】:

我有以下结构和填充它的代码:

typedef struct {
    char name[CONTACT_NAME_SIZE];
    char surname[CONTACT_SURNAME_SIZE];
    char address[CONTACT_ADDRESS_SIZE];
    char phoneNumber[CONTACT_PHONENUMBER_SIZE];
} Contact;

...

char buffer[1024];
char phonebookItem[50];

printf("Name (max %d characters): ", CONTACT_NAME_SIZE);
fgets(buffer, sizeof(buffer), stdin);
memcpy(phonebookItem, buffer, sizeof(phonebookContacts[id].name));
strcpy(phonebookContacts[id].name, phonebookItem);

printf("Surname (max %d characters): ", CONTACT_SURNAME_SIZE);
fgets(buffer, sizeof(buffer), stdin);
memcpy(phonebookItem, buffer, sizeof(phonebookContacts[id].surname));
strcpy(phonebookContacts[id].surname, phonebookItem);

printf("Address (max %d characters): ", CONTACT_ADDRESS_SIZE);
fgets(buffer, sizeof(buffer), stdin);
memcpy(phonebookItem, buffer, sizeof(phonebookContacts[id].address));
strcpy(phonebookContacts[id].address, phonebookItem);

printf("Phone number (max %d characters): ", CONTACT_PHONENUMBER_SIZE);
fgets(buffer, sizeof(buffer), stdin);
memcpy(phonebookItem, buffer, sizeof(phonebookContacts[id].name));
strcpy(phonebookContacts[id].phoneNumber, phonebookItem);

问题是当我为第一个字段输入数据时,一切正常。但是当我为下一个字段输入数据时,我输入的所有内容(第一个和第二个输入)都会写入第一个字段,依此类推...

例子:

Name (max 10 characters): 123456789*123456789
phonebookContacts[id].name = 123456789* -> OK
Surname (max 15 characters): 123456789*123456789*
phonebookContacts[id].name = 123456789*123456789*12345
phonebookContacts[id].surname = 123456789*12345

为什么会被覆盖?

【问题讨论】:

  • 如果用户输入太多输入,像这样使用memcpy() 将导致未定义的行为,因为您的字符串将未终止,但除此之外,它不会按照您的要求执行。您的代码中还有一些其他错误,可能从糟糕的内存管理到试图错误地打印这些东西。没有足够的信息进行诊断。
  • 你为什么还要使用 memcpy?
  • 我使用 memcpy 是因为我尝试了几种方法来做我想做的事,只有 memcpy 有效(它“只是”覆盖了所有内容)。我需要将字符串从缓冲区复制到结构字段,但我必须管理对太长字符串的保护。
  • ...并且您“管理对太长字符串的保护”是错误的。如果没有终止,memcpy 不会终止您的字符串。确保在覆盖后在每个覆盖缓冲区的最后一个位置插入一个零字节(ASCII NUL 字符),例如surname[CONTACT_SURNAME_SIZE - 1] = 0;
  • 您总是可以采取激进的步骤,实际检查输入 before 的长度以尝试复制它,如果太长则简单地拒绝它。这可能比默默地截断输入更好(如果你拒绝了一半的地址,你将如何成功地给某人发邮件?)即使用户故意选择不遵守说明。

标签: c struct memcpy overwrite


【解决方案1】:

而不是这个:

fgets(buffer, sizeof(buffer), stdin);
memcpy(phonebookItem, buffer, sizeof(phonebookContacts[id].name));
strcpy(phonebookContacts[id].name, phonebookItem);

试试这个:

memset(buffer, 0, sizeof(buffer));  // zero out all of buffer
fgets(buffer, sizeof(buffer), stdin); // accept up to n-1 input characters (last zero stays)
strncpy(phonebookContacts[id].name, buffer, CONTACT_NAME_SIZE-1);  // copy data

或:

memset(buffer, 0, sizeof(buffer));  // zero out all of buffer
fgets(buffer, CONTACT_NAME_SIZE, stdin); // accept up to field-specific number of  input characters
strcpy(phonebookContacts[id].name, buffer);  // copy data

假设缓冲区的大小总是大于您可能提供的任何输入,并且它的大小也大于或等于您正在输入的任何字段中的最大值。

编辑:为清楚起见添加了两个选项

【讨论】:

  • 是的,我之前已经尝试过这个,但是当我使用字段大小而不是缓冲区大小时,如果标准输入大于我想要的最大大小,它将溢出到另一个字段。我使用缓冲区来防止输入过长,但在你的情况下,如果输入太长,我不知道如何从缓冲区中取出前 x 个字符并将其放入 struct 字段。
  • 函数是:strncpy(to, from, number_of_chars),如果在复制'number_of_bytes'之前在'from'字符串中找到零字节,它将停止。此外,例如,您可以使用 CONTACT_NAME_SIZE 代替 sizeof(buffer)。
  • sizeof(buffer)-1 与 fgets() 一起使用是不正确的。 fgets() 将读取最多 size-1 个字节,然后 null 终止缓冲区,因此使用完整大小是正确的。实际上是 strncpy() 需要 size-1。
  • 这是故意的,因为看起来这些尺寸是任意的。该程序无法控制用户输入的内容。至于 strncpy,它只会在给定的字节数处停止,如果在输入处找不到一个,则不会附加零,这使得两种情况下都需要 size-1,最终以最大长度为零结尾字符串。
  • 我的母语不是英语,但经过编辑,我希望我的意思从代码中可以清楚:P
猜你喜欢
  • 2018-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-23
  • 1970-01-01
相关资源
最近更新 更多