为什么这个结构数组会覆盖 char * 但不会覆盖 int?

Why does this array of structures overwrite char * but not int?

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

程序有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);
    } 
}

main.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 保持不变?我该如何解决这个问题?

您将 part_name 成员声明为 char *,并在 insert 函数中为其分配了局部数组的地址。当函数 returns 时,该数组超出范围并且存储的指针变为无效。随后尝试使用该指针触发 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);      

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 <stdlib.h> 以使用 malloc()