【问题标题】:Why does this array of structures overwrite char * but not int? [duplicate]为什么这个结构数组会覆盖 char * 而不是 int? [复制]
【发布时间】:2021-07-22 14:48:24
【问题描述】:

我编写了一个程序,它利用结构数组来维护一种具有不同选项的“数据库”程序,可用于操作“数据库”。

程序有4种操作模式,如果用户进入:

  1. 'i'数据可以插入到“数据库”中。
  2. 's' 在“数据库”中搜索具有项目部件号的部件。
  3. 'u' 根据商品的部件号更新数据库中的某些内容。
  4. 'p' 打印整个“数据库”。

这是由 3 个文件组成的代码:

database.h

#ifndef DATABASE
#define DATABASE

struct db
{
       int  part_number;
       char *part_name;
       int  part_quantity;
};

extern struct db database[50];

extern void insert(int i);

extern int search(int i);

extern int update(int i);

extern int print(int i);

#endif

database.c

#include <string.h>
#include <stdio.h>
#include "database.h"

struct db database[50];    

void insert(int i)
{
     char name_of_part[21], c; 
  
     printf("%p\n", &database[i].part_name);     

     printf("\n");
     printf("Enter a part number: ");
     scanf("%d", &database[i].part_number);
     
     while((c = getchar()) != '\n' && c != EOF); // flush stdin
 
     printf("Enter a part name: ");
     fgets(name_of_part, 20, stdin);      
    
     printf("Enter quantity of part: ");
     scanf("%d", &database[i].part_quantity);     
     
     database[i].part_name = name_of_part;

     printf("\n");
}

int search(int i)
{    
     int input;
     printf("\n");
     printf("Enter a part number: ");
     scanf("%d", &input);
     
     for (int j = 0; j <= i; j++)
     {    
         if (database[j].part_number == input)
         {
            printf("Part name: %s\n", database[j].part_name);
            printf("Quantity on hand: %d\n", database[j].part_quantity);
            return 0;
         }         
     }
     printf("Part not found.\n"); 
}    

int update(int i)
{ 
    int input, quantity;
  
    printf("\n"); 

    printf("Enter part number: "); 
    scanf("%d", &input);
    
    for (int j = 0; j <= i; j++)
    {
        if (database[j].part_number == input)
        {
           printf("Enter part quantity: ");
           scanf("%d", &quantity);
          
           database[j].part_quantity = quantity;             
           return 0;
        }   
    }
    printf("Part number not found.");            
}    

int print(int i)
{
    for (int j = 0; j < i; j++)
    {
         printf("Part number: %d\n Part name: %s\n Part quantity: %d\n", database[j].part_number, database[j].part_name,database[j].part_quantity);
    } 
}

ma​​in.c

#include <stdio.h>
#include <string.h>
#include "database.h"

int main()
{   
     int i = 0;  
     char code;   
 
     while (1)
     {         
         printf("Enter a function code: ");
         scanf(" %c", &code);       

         switch (code)
         {      
                case 'i':
                     insert(i);
                     i += 1;
                     break;
               
                case 's':
                     search(i);
                     break;

                case 'u':
                     update(i);
                     break;
                case 'p':
                     print(i);
                     break;     
         }      
          
     }      
     
     return 0;
}

我遇到的问题是,当我插入“数据库”时,每个结构中的名称都会被覆盖。例如:

Enter a function code: i

Enter a part number: 111
Enter a part name: 111
Enter quantity of part: 111

Enter a function code: i

Enter a part number: 222
Enter a part name: 222
Enter quantity of part: 222

Enter a function code: p
Part number: 111
Part name: 222
Part quantity: 111

Part number: 222
Part name: 222
Part quantity: 222

Enter a function code: 

正如您首先看到的,我在“数据库”中插入了一些新内容,记下“部件名称”,即“111”。

接下来我将其他内容插入数据库 这次“零件名称”是“222”。

最后我打印了整个“数据库”,我感到困惑的是为什么零件名称现在重叠了。但这是为什么呢?所有其他成员,例如 part_number 和 part_quantity 在两个插入操作中都保持不变,那么为什么 char *part_name 保持不变?我该如何解决这个问题?

【问题讨论】:

  • database[i].part_name = name_of_part 是问题所在:name_of_part 是一个 local 变量,一旦函数返回,它的生命周期就会结束,导致指针无效。
  • database[i].part_name = name_of_part; 这是非法的。 name_of_part 是该函数中的一个局部非静态变量。当您离开该功能时,它的生命周期就结束了。这会导致未定义的行为
  • 您需要在each结构元素中分配内存,并将输入的字符串数据复制到它。 strdup 函数可以同时执行这两种操作,但是当您删除/删除该元素时,您需要 free() 每个元素的 part_name

标签: c struct structure-of-arrays


【解决方案1】:

您将part_name 成员声明为char *,并在insert 函数中为其分配本地数组的地址。当函数返回时,该数组超出范围并且存储的指针变得无效。随后尝试使用该指针触发undefined behavior

part_name改为数组:

struct db
{
       int  part_number;
       char part_name[21];
       int  part_quantity;
};

然后直接写:

 printf("Enter a part name: ");
 fgets(database[i].part_name, 21, stdin);      

【讨论】:

  • @MikeCAT 复制到错误的 arg。固定。
  • 感谢您的回答
  • @programmerc3981143 很高兴我能提供帮助。如果您觉得有用,请随时 accept this answer
【解决方案2】:

线

database[i].part_name = name_of_part;

不好。这是分配一个指向非静态局部变量的指针。该变量在从函数返回并取消引用指向该变量的指针时结束其生命周期是非法的。

除此之外,您必须复制字符串。如果你的系统支持strdup(),可以这样:

database[i].part_name = strdup(name_of_part);

如果不支持strdup(),或者您想坚持标准,您可以这样做:

database[i].part_name = malloc(strlen(name_of_part) + 1); /* +1 for ther terminating null-character */
if (database[i].part_name != NULL)
{
    strcpy(database[i].part_name, name_of_part);
}

添加#include &lt;stdlib.h&gt; 以使用malloc()

【讨论】:

  • 感谢您的回答
猜你喜欢
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
  • 1970-01-01
  • 2018-04-24
  • 1970-01-01
  • 2016-06-22
  • 2011-08-20
  • 1970-01-01
相关资源
最近更新 更多