若结构中的字符大小为30或更大,则程序终止



HEADER FILE-如果我将字符大小从30更改为20或更小,代码可以正常工作,但如果字符大小为30或更高,则在主代码中第5个大小写的for循环之后不会执行。

struct Data
{
int Emp_id;
char Emp_name[30];
char Emp_city[30];
};
void input(struct Data emp[], int n)
{
for (int i = 0; i < n; i++)
{
printf("enter employee id of %d employee: n", i + 1);
scanf("%d", &emp[i].Emp_id);
fflush(stdin);
printf("enter employee name of %d employee: n", i + 1);
gets(emp[i].Emp_name);
fflush(stdin);
printf("enter employee city of %d employee: n", i + 1);
gets(emp[i].Emp_city);
}
}

MAIN CODE-add函数在第五种情况下执行,如果头文件结构中的字符大小为30或更大,则循环停止。如果我减少一次迭代,使循环像这样——for(int I=n-5;I<n-1;I++),但包括最后一次迭代会终止程序,显示函数不会执行,那么代码也会工作。

#include <stdio.h>
#include <string.h>
#include "data.h"
void find(struct Data emp[], int n);
void sortid(struct Data emp[], int n);
void sortAlp(struct Data emp[], int n);
void count(struct Data emp[], int n);
void add(struct Data emp[], int n);
void display(struct Data emp[], int n);
int main(void)
{
int n;
int a;
printf("enter the number of employees:n");
scanf("%d", &n);
struct Data emp[n];
input(emp, n);
printf("enter the operation you want to perform:n");
printf("1 - to find employee record from employee idn");
printf("2 - to sort employee record on basis of employee idn");
printf("3 - to alphabetically sort array of charactersn");
printf("4 - to count the number of employees in databasen");
printf("5 - to add 5 more recordsn");
scanf("%d", &a);
switch (a)
{
case 1:
find(emp, n);
break;
case 2:
sortid(emp, n);
display(emp, n);
break;
case 3:
sortAlp(emp, n);
display(emp, n);
break;
case 4:
count(emp, n);
break;
case 5:
add(emp, n);
break;
}
return 0;
}
void find(struct Data emp[], int n)
{
int a;
int count = 0;
printf("Enter the employee id: ");
scanf("%d", &a);
for (int i = 0; i < n; i++)
{
if (a == emp[i].Emp_id)
{
printf("Employee id: %dn", emp[i].Emp_id);
printf("Employee name: %sn", emp[i].Emp_name);
printf("Employee city: %sn", emp[i].Emp_city);
count++;
}
}
if (count == 0)
{
printf("Employee id does not exist");
}
}
void sortid(struct Data emp[], int n)
{
int temp;
char temp2[30];
char temp3[30];
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (emp[i].Emp_id > emp[j].Emp_id)
{
temp = emp[i].Emp_id;
emp[i].Emp_id = emp[j].Emp_id;
emp[j].Emp_id = temp;
strcpy(temp2, emp[i].Emp_name);
strcpy(emp[i].Emp_name, emp[j].Emp_name);
strcpy(emp[j].Emp_name, temp2);
strcpy(temp3, emp[i].Emp_city);
strcpy(emp[i].Emp_city, emp[j].Emp_city);
strcpy(emp[j].Emp_city, temp3);
}
}
}
}
void sortAlp(struct Data emp[], int n)
{
int temp2;
char temp[30];
char temp3[30];
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (emp[i].Emp_name[0] > emp[j].Emp_name[0])
{
strcpy(temp, emp[i].Emp_name);
strcpy(emp[i].Emp_name, emp[j].Emp_name);
strcpy(emp[j].Emp_name, temp);
temp2 = emp[i].Emp_id;
emp[i].Emp_id = emp[j].Emp_id;
emp[j].Emp_id = temp2;
strcpy(temp3, emp[i].Emp_city);
strcpy(emp[i].Emp_city, emp[j].Emp_city);
strcpy(emp[j].Emp_city, temp3);
}
}
}
}
void count(struct Data emp[], int n)
{
int k;
for (int i = 0; i < n; i++)
{
k = i;
}
printf("number of employees: %dn", k + 1);
}
void add(struct Data emp[], int n)
{
n = n + 5;
for (int i = n - 5; i < n; i++)
{
printf("enter employee id of %d employee: n", i + 1);
scanf("%d", &emp[i].Emp_id);
fflush(stdin);
printf("enter employee name of %d employee: n", i + 1);
gets(emp[i].Emp_name);
fflush(stdin);
printf("enter employee city of %d employee: n", i + 1);
gets(emp[i].Emp_city);
}
//Program stops here without executing display
display(emp, n);
}
void display(struct Data emp[], int n)
{
for (int i = 0; i < n; i++)
{
printf("employee id of %d employee: %d n", (i + 1), emp[i].Emp_id);
printf("employee name of %d employee: %s n", (i + 1), emp[i].Emp_name);
printf("employee city of %d employee: %s n", (i + 1), emp[i].Emp_city);
}
}

对数组大小的依赖是巧合,缓冲区溢出总是在第五种情况下发生。

在程序中,读取n,然后分配一个n条目数组。n的后续更改(如果有)(实际上没有,add中的操作会更改副本)不会更改数组大小。通过这种方式,add通过数组写入数据,这是被禁止的,可能会使程序崩溃,甚至更糟。

您需要的是动态内存分配,例如:

// create an array of n entries
struct Data *emp = malloc(n * sizeof(struct Data));
// grow it (or shrink) to new_n entries
emp = realloc(emp, new_n * sizeof(struct Data));
n = new_n;
// destroy it
free(emp);
emp = NULL; // safeguard, should be right after free

请注意,在增长数组时,需要更改代码中使用的实际empn,而函数只获得副本(在emp的情况下是指针的副本,而不是整个数组的副本)。因此,要么在调用add之前在main中执行此操作,要么将其更改为接受指向这些变量的指针,让它自己执行此操作。

printf("enter the number of employees:n");
scanf("%d", &n);
struct Data emp[n];

这里有一个问题:不能只读取n,然后声明emp[n]元素的数组。您在运行时读取它,但编译器需要知道要为多少emp分配空间。编译器在编译时需要这些信息。它不能等到scanf()运行。

您必须使用常数值,或使用动态分配,如下面的//1 //2//3

#define   EMP_SIZE 42
struct Data emp1[EMP_SIZE];  // 1
struct Data emp2[42];  // 2
n = n + 5; // 3
struct Data* emp3 = (struct Data*) malloc(n*sizeof(struct Data));

出于同样的原因

void add(struct Data emp[], int n)
{
n = n + 5;
for (int i = n - 5; i < n; i++)
{}

也不起作用。我相信你假设设置n = n + 5;会以某种方式扩展数组并分配5个新的emp。不会的。它只会将n(一个int)设置为n + 5。在for中,您正试图重写这些新的emp记录。

好吧,没有新的记录,你的程序很快就会崩溃。

有关代码的更多信息

你现在可能有点厌倦了到处写struct Data。一般来说,人们习惯于写

typedef struct
{
int  Emp_id;
char Emp_name[30];
char Emp_city[30];
}   Data;

此命令将Data定义为匿名struct。它不创建一个,只是为它、为整个集合定义一个名称。

你可以写

void input(Data emp[], int n);

而不是

void input(struct Data emp[], int n);

标头的使用

通常,.h文件包含定义和原型。这个想法是在两个文件的集合中创建代码。标头包含声明和原型。CCD_ 27文件具有用于函数的代码。

第三个文件承载main()。为什么?因为以这种方式编写,您有许多实现main()并测试程序不同功能的.c文件。

当函数正常时,你可以保留(或出售)函数的编译代码,以及带有声明的.h,这样其他人就可以在他们的程序中使用它,只需包含标题并将链接器指向编译形式的函数代码。这种编译形式被称为library。这与通过包括CCD_ 34来使用CCD_。在Unix中,libc是库,stdlib.h是头。

绕过数据

void find(struct Data emp[], int n);
void sortid(struct Data emp[], int n);
void sortAlp(struct Data emp[], int n);
void count(struct Data emp[], int n);
void add(struct Data emp[], int n);
void display(struct Data emp[], int n);

缩小代码,所有函数都处理一个struct Data数组,而n是数组大小。它被称为容器,是继简单array本身之后最常见的结构。

所以你可以写

typedef struct
{
int     id;
char    name[20];
char    city[20];
}   Employee;
typedef struct
{
unsigned    N;
unsigned    capacity;
Employee*   E;
}   Data;

这里,DataEmployee的容器。但在Data内部是N大小的组件,它真的很方便。这在OOP文献中被称为封装。

例如,重构代码

我将重新排列您的代码并重新实现一些函数,这样您就可以比较这两种方式。写这篇文章还有很多其他的方式,我甚至不是说这篇是好的,或者你的是坏的。

修改后的页眉

// f1-data.h
typedef struct
{
int     id;
char    name[20];
char    city[20];
}   Employee;
typedef struct
{
unsigned    N;
unsigned    capacity;
Employee*   E;
}   Data;
Data*       create_Data(unsigned);
Data*       delete_Data(Data*);
int         add(Employee*, Data*);
int         add5(Data*);
int         count(Data*);
void        display(Data*,const char*);
Employee*   find(int,Data*);
Employee*   input();
//void        sortid(Data*);
//void        sortAlp(Data*);
// f1-data.h end

关于变化:

  • Data现在是Employee的集合。从您的代码中可以看出,大小必须是动态的,因此Data有一个字段capacity,它包含当前容量,还有一个字段N包含当前大小。E是Employee的数组。一个简短的名字很有帮助,因为它被使用了很多次。我将编写add5()作为扩展结构的常见方法的示例
  • create_data()返回指向具有要求容量的数据集的指针
  • CCD_ 52返回CCD_。其目的是提供一种在删除集合后使指针无效的简单方法
  • find()返回指向具有给定idNULLEmployee的指针。这种方式更实用,而不是每次调用都向屏幕写入的函数
  • add5()被实现为如何扩展阵列的示例
  • input()返回一个指向Employee的指针,因此我们可以用数据测试程序,而根本不需要交互
  • 在结构内部的字段中不需要CCD_ 61前缀。我们可以想象,Employeestruct内部的字段是Employee数据
  • 将CCD_ 65改为CCD_。建议任何程序都不要在名称开头使用一个或多个下划线。这些在某种程度上是留给库实现者的
  • display()现在有一个标题字符串,因为它在示例中很有用
  • 文件.c中的函数代码命名为h.。我将按顺序全部3个,以便更容易地剪切和粘贴您想要测试的网站案例

main()用于测试

int main(void)
{
Data* set1 = create_Data(4);
display(set1, "empty. (just testing)");
add5(set1);
display(set1, "empty. (added 5 in cap.)");
// now inserts until error
printf("inserting employees until errorn");
Employee* e = NULL;
while (set1->N < set1->capacity)
{   e = input();
add(e, set1);
free(e);
}
display(set1, "Now set should be full");
set1 = delete_Data(set1);
}

逻辑:

  • 创建一个容量为4Employee的集合
  • 调用display()
  • 该集合扩展为5条以上的记录并显示
  • 调用调用input()并插入记录,直到出现错误
  • 调用display()以显示现在的完整集合
  • 则该集合被删除

测试输出

empty. (just testing)
0 Employees [Cap. 4]

empty. (added 5 in cap.)
0 Employees [Cap. 9]

inserting employees until error
Now set should be full
9 Employees [Cap. 9]
1         420         Jhonny 420 Jr [ City  420 ]
2         421         Jhonny 421 Jr [ City  421 ]
3         422         Jhonny 422 Jr [ City  422 ]
4         423         Jhonny 423 Jr [ City  423 ]
5         424         Jhonny 424 Jr [ City  424 ]
6         425         Jhonny 425 Jr [ City  425 ]
7         426         Jhonny 426 Jr [ City  426 ]
8         427         Jhonny 427 Jr [ City  427 ]
9         428         Jhonny 428 Jr [ City  428 ]

完整代码(3个文件)

// f1-data.h
typedef struct
{
int     id;
char    name[20];
char    city[20];
}   Employee;
typedef struct
{
unsigned    N;
unsigned    capacity;
Employee*   E;
}   Data;
Data*       create_Data(unsigned);
Data*       delete_Data(Data*);
int         add(Employee*, Data*);
int         add5(Data*);
int         count(Data*);
void        display(Data*,const char*);
Employee*   find(int,Data*);
Employee*   input();
//void        sortid(Data*);
//void        sortAlp(Data*);
// f1-data.h end

// f1-data.c
#include <stdio.h>
#include <stdlib.h>
#include "f1-data.h"
int add(Employee* E, Data* S)
{
// add Employee E
if (S->N == S->capacity) return -1;  // full
// space we have: copy Employee
S->E[S->N] = *E;
S->N += 1;  // count one
return S->N;
}
int add5(Data* Set)
{   // adds 5 records to Set
if (Set == NULL) return -1;
int   n_size = 5 + Set->capacity;
Employee* temp   = (Employee*)realloc(Set->E, n_size * sizeof(Employee));
if (temp == NULL) return -2; // could not extend?
Set->E = temp; // that is all
Set->capacity = n_size;
return 0;
}
int         count(Data* S){ return S->N; }
Data*       create_Data(unsigned cap)
{ 
Data* set = (Data*)malloc(cap * sizeof(Data));
set->N    = 0; // empty
set->capacity = cap;
set->E    = (Employee*)malloc(cap * sizeof(Employee));
return set;
}
Data*       delete_Data(Data* set)
{
if (set == NULL) return NULL;
free(set->E); // frees Employees first
free(set);    
return NULL;
}
void        display(Data* Set, const char* msg)
{
if (msg != NULL) printf("%sn", msg);
printf("%d Employees [Cap. %u]nn", Set->N, Set->capacity);
for (unsigned i = 0; i < Set->N; i++)
printf("
%3u    %8d  %20s [ %s ]n",
i + 1,
Set->E[i].id,
Set->E[i].name,
Set->E[i].city
);
printf("n");
}
Employee*   find(int id, Data* S)
{
for (unsigned i = 0; i < S->N; i++)
if (id == S->E[i].id)
{   // found
Employee* found = (Employee*)malloc(sizeof(Employee));
*found          = S->E[i];
return found;
}
return NULL;
}
Employee*   input()
{  // returns a new Employee record
static int id    = 420;
Employee*  new_E = (Employee*)malloc(sizeof(Employee));
new_E->id        = id;
sprintf(new_E->name, "Jhonny%4d Jr", id);
sprintf(new_E->city, "City %4d", id);
id += 1;
return new_E;
}
//void        sortid(Data* Set){};
//void        sortAlp(Data* Set){};
// f1-data.c end
// f1.c
#include <stdio.h>
#include <stdlib.h>
#include "f1-data.h"
int main(void)
{
Data* set1 = create_Data(4);
display(set1, "empty. (just testing)");
add5(set1);
display(set1, "empty. (added 5 in cap.)");
// now inserts until error
printf("inserting employees until errorn");
Employee* e = NULL;
while (set1->N < set1->capacity)
{   e = input();
add(e, set1);
free(e);
}
display(set1, "Now set should be full");
set1 = delete_Data(set1);
}
//f1.c end

关于排序

请注意,排序函数只是更改排序字段,因此您应该只传递compare函数,并编写一个排序。或者,只调用qsort()

审阅者注意:我总是投射malloc()返回的指针,我知道一些90年代的文本(如C-FAQ)会针对它进行写操作。无需向我指出这一点。

相关内容

  • 没有找到相关文章

最新更新