要求:
- 逐行读取指定文件中的数据,解析后保存在顺序表中。其中,文件中每行数据格式为“学号,姓名,年 龄”,比如“10225048,张三,24”(提示:采用顺序表结构时,顺序表中每个表元素包含三类信息:学号,姓名,和年龄;采用单链表结构时,单链表中每个结点的数据域包含三类信息:学号,姓名,和年龄),
- 根据键盘输入进行相关操作,比如,若键盘输入为“P3”,则打印出第3项信息(注意:采用顺序表结构时,第3项数据对应下标为2的表元素;采用单链表结构时,第3项数据对应链表中第3个结点的信息;);若键盘输入为“D3”,则删除第3个表元素;若键盘输入为“I3,10225038,张四,24”,则在第3项前插入一个学生的信息(10225038,张四,24)。
实现代码:
- 头文件
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <conio.h>
#define LIST_INCREASEMENT 10
#define ORIGINA_DATA_NUM 8
#define SIZE 256
typedef struct
{
char id[SIZE] = { 0 };
char name[SIZE] = { 0 };
char age[SIZE] = { 0 };
}student;
typedef struct
{
student *element;
int list_curr_length;
int list_size;
}SqList;
typedef struct LNode
{
student *data;
struct LNode *next;
}LinkNode;
int SqListMain(void);
int LinkedListMain(void);
void SqListInstr(void);
void DisplaySqList(SqList *L);
void InitSqList(SqList *&L);
void SqListEmpty(SqList *L);
void SqListLength(SqList *L);
void DestroySqList(SqList *&L);
bool SqListInsert(SqList *&L, int i, student e);
bool SqListDelete(SqList *&L, int i);
bool SqListGetInsert(SqList *&L);
bool PrintSqList(SqList *L, int i);
int LinkedListMain(void);
void LinListLength(LinkNode *L);
void LinListInstr(void);
void InitLinList(LinkNode *&L);
void DisplayLinList(LinkNode *L);
void DestroyLinList(LinkNode *&L);
void EmptyLinList(LinkNode *L);
bool LinListGetInsert(LinkNode *&L);
bool LinListDelete(LinkNode *&L, int i);
bool LinListInsert(LinkNode *&L, int i, student e);
- Sequence List 实现:
#include "head.h"
SqList *L;
bool flag_1 = false;
void InitSqList(SqList *&L)
{
L = (SqList *)malloc(sizeof(SqList));
L->element = (student *)malloc(sizeof(student) * 100);
L->list_size = 100;
L->list_curr_length = 0;
}
void DestroySqList(SqList *&L)
{
free(L);
}
void SqListEmpty(SqList *L)
{
if (L->list_curr_length == 0)
printf("\n顺序表为空。\n\n");
else
printf("\n顺序表不为空。\n\n");
return;
}
void SqListLength(SqList *L)
{
printf("\n顺序表长度为:%d\n\n", L->list_curr_length);
return;
}
void DisplaySqList(SqList *L)
{
if (!L->list_curr_length)
{
printf("列表为空,无法打印。\n");
return ;
}
printf("----------------------------\n\n");
for (int i = 0; i < L->list_curr_length; i++)
printf("%s, %s, %s\n", L->element[i].id, L->element[i].name, L->element[i].age);
printf("----------------------------\n");
return;
}
bool PrintSqList(SqList *L, int i)
{
if (i < 1 || i > L->list_curr_length)
{
printf("输入有误,当前顺序表长度为%d,请重新输入。\n", L->list_curr_length);
return false;
}
i--;
printf("\n%s, %s, %s\n", L->element[i].id, L->element[i].name, L->element[i].age);
printf("\n");
return true;
}
/*
bool SqListGetElem(SqList *L, int i)
{
if (i < 1 || i > L->list_curr_length)
{
printf("输入有误,当前顺序表长度为%d,请重新输入。\n", L->list_curr_length);
return false;
}
i--;
printf("\n%s, %s, %s\n", L->element[i].id, L->element[i].name, L->element[i].age);
printf("\n");
return true;
}
*/
/*
int SqListLocateElem(SqList *L, student e)
{
int i = 0;
while (i < L->list_curr_length && L->element[i].id != e.id)
i++;
if (i >= L->list_curr_length)
return 0;
else
return i + 1;
}
*/
bool SqListInsert(SqList *&L, int i, student e)
{
int j;
if (i < 1 || i > L->list_curr_length + 1)
{
printf("输入有误,当前顺序表长度为%d,请重新输入。\n", L->list_curr_length);
return false;
}
i--;
if (L->list_curr_length >= L->list_size)
{
student *new_element;
new_element = (student *)realloc(L->element, L->list_size + LIST_INCREASEMENT);
L->element = new_element;
L->list_size += LIST_INCREASEMENT;
}
for (j = L->list_curr_length; j > i; j--)
{
strcpy(L->element[j].age, L->element[j - 1].age);
strcpy(L->element[j].id, L->element[j - 1].id);
strcpy(L->element[j].name, L->element[j - 1].name);
}
strcpy(L->element[i].id, e.id);
strcpy(L->element[i].name, e.name);
strcpy(L->element[i].age, strcat(e.age, "\n"));
/*
memcpy(L->element[i].id, e.id, strlen(e.id) + 1);
memcpy(L->element[i].name, e.name, strlen(e.name) + 1);
memcpy(L->element[i].age, e.age, strlen(e.age) + 1);
*/
L->list_curr_length++;
if (flag_1)
{
printf("成功插入节点,当前节点列表为:\n\n");
DisplaySqList(L);
}
return true;
}
bool SqListDelete(SqList *&L, int i)
{
int j;
if (i < 1 || i > L->list_curr_length)
{
printf("输入有误,当前顺序表长度为%d,请重新输入。\n", L->list_curr_length);
return false;
}
i--;
for (j = i; j < L->list_curr_length - 1; j++)
{
strcpy(L->element[j].age, L->element[j + 1].age);
strcpy(L->element[j].id, L->element[j + 1].id);
strcpy(L->element[j].name, L->element[j + 1].name);
}
L->list_curr_length--;
printf("成功删除节点,当前节点列表为:\n\n");
DisplaySqList(L);
return true;
}
void SqListInstr(void)
{
printf("\n操作说明:\n");
printf("----------------------------\n\n");
printf(" QQ: 退出\n\n");
printf(" TT: 打印操作说明\n\n");
printf(" RR: 删除整个列表\n\n");
printf(" EE: 判断列表是否为空\n\n");
printf(" LL: 返回列表长度\n\n");
printf(" SS: 打印完整列表\n\n");
printf(" NN: 重新初始化列表\n\n");
printf("I+数字: 插入新节点\n\n");
printf("P+数字: 打印单个节点\n\n");
printf("D+数字: 删除单个节点\n\n");
printf("----------------------------\n\n");
return;
}
bool SqListGetInsert(SqList *&L)
{
FILE *fp = NULL;
student insert_elem;
char e_oneline[1024], *temp;
if ((fp = fopen("data.txt", "r")) == NULL)
{
printf("error!\n");
return false;
}
int i = 1;
while (!feof(fp) && i < ORIGINA_DATA_NUM + 1)
{
fgets(e_oneline, 1024, fp);
strcpy(insert_elem.id, strtok(e_oneline, ","));
strcpy(insert_elem.name, strtok(NULL, ","));
strcpy(insert_elem.age, strtok(NULL, ","));
/*
memcpy(insert_elem.id, temp, strlen(temp) + 1);
memcpy(insert_elem.name, temp, strlen(temp) + 1);
memcpy(insert_elem.age, temp, strlen(temp) + 1);
*/
SqListInsert(L, i, insert_elem);
i++;
}
fclose(fp);
printf("\n初始化成功,当前节点列表为:\n\n");
DisplaySqList(L);
flag_1 = true;
return true;
}
int SqListMain(void)
{
student insert_elem;
int input_t;
char input_o;
SqListInstr();
InitSqList(L);
SqListGetInsert(L);
printf("请输入指令:");
scanf(" %c%d", &input_o, &input_t);
if (input_o == 'I')
{
printf("\n请输入待插入项: ");
scanf("%s %s %s", insert_elem.id, insert_elem.name, insert_elem.age);
// printf("%s, %s, %s, %c, %d\n", insert_elem.id, insert_elem.name, insert_elem.age, input_o, input_t);
}
while (input_o != 'Q')
{
switch (input_o)
{
case 'P':
PrintSqList(L, input_t);
break;
case 'D':
SqListDelete(L, input_t);
break;
case 'I':
SqListInsert(L, input_t, insert_elem);
break;
case 'R':
DestroySqList(L);
break;
case 'E':
SqListEmpty(L);
break;
case 'L':
SqListLength(L);
break;
case 'S':
DisplaySqList(L);
break;
case 'T':
SqListInstr();
break;
case 'N':
InitSqList(L);
flag_1 = false;
SqListGetInsert(L);
flag_1 = true;
break;
default:
printf("指令有误,请重新输入。\n");
break;
}
printf("请输入指令:");
scanf(" %c%d", &input_o, &input_t);
if (input_o == 'I')
{
printf("\n请输入待插入项: ");
scanf("%s %s %s", insert_elem.id, insert_elem.name, insert_elem.age);
// printf("%s, %s, %s, %c, %d\n", insert_elem.id, insert_elem.name, insert_elem.age, input_o, input_t);
}
}
return 0;
}
- Linked List 实现:
#include "head.h"
LinkNode *L;
bool flag_2 = false;
void InitLinList(LinkNode *&L)
{
L = (LinkNode *)malloc(sizeof(LinkNode));
L->data = (student *)malloc(sizeof(student));
L->next = NULL;
}
void DestroyLinList(LinkNode *&L)
{
LinkNode *pre = L, *p = pre->next;
while (p != NULL)
{
free(pre);
pre = p;
p = pre->next;
}
free(pre); //此时p为NULL,pre指向尾结点,释放它
}
void EmptyLinList(LinkNode *L)
{
if (!L->next)
printf("\n顺序表为空。\n\n");
else
printf("\n顺序表不为空。\n\n");
return;
}
void LinListLength(LinkNode *L)
{
LinkNode *p = L; int i = 0;
while (p->next != NULL)
{
i++;
p = p->next;
}
printf("\n链表长度为:%d\n\n", i);
return;
}
bool LinListDelete(LinkNode *&L, int i)
{
int j = 0;
LinkNode *p = L, *q;
if (i <= 0) return false; //i错误返回假
while (j < i - 1 && p != NULL) //查找第i-1个结点
{
j++;
p = p->next;
}
if (p == NULL) //未找到位序为i-1的结点
return false;
else //找到位序为i-1的结点p
{
q = p->next; //q指向要删除的结点
if (q == NULL)
return false; //若不存在第i个结点,返回false
p->next = q->next; //从单链表中删除q结点
free(q); //释放q结点
}
printf("\n成功删除节点,当前节点列表为:\n\n");
DisplayLinList(L);
return true;
}
bool LinListGetInsert(LinkNode *&L)
{
FILE *fp = NULL;
student insert_elem;
char e_oneline[1024], *temp;
if ((fp = fopen("data.txt", "r")) == NULL)
{
printf("error!\n");
return false;
}
int i = 1;
while (!feof(fp) && i < ORIGINA_DATA_NUM + 1)
{
fgets(e_oneline, 1024, fp);
strcpy(insert_elem.id, strtok(e_oneline, ","));
strcpy(insert_elem.name, strtok(NULL, ","));
strcpy(insert_elem.age, strtok(NULL, ","));
/*
memcpy(insert_elem.id, temp, strlen(temp) + 1);
memcpy(insert_elem.name, temp, strlen(temp) + 1);
memcpy(insert_elem.age, temp, strlen(temp) + 1);
*/
LinListInsert(L, i, insert_elem);
i++;
}
fclose(fp);
printf("\n初始化成功,当前节点列表为:\n\n");
DisplayLinList(L);
flag_2 = true;
return true;
}
void DisplayLinList(LinkNode *L)
{
LinkNode *p = L->next;
printf("----------------------------\n\n");
while (p != NULL)
{
printf("%s, %s, %s\n", p->data->id, p->data->name, p->data->age);
p = p->next;
}
printf("----------------------------\n\n");
}
void LinListInstr(void)
{
printf("\n操作说明:\n");
printf("----------------------------\n\n");
printf(" QQ: 退出\n\n");
printf(" TT: 打印操作说明\n\n");
printf(" RR: 删除整个列表\n\n");
printf(" EE: 判断列表是否为空\n\n");
printf(" LL: 返回列表长度\n\n");
printf(" SS: 打印完整列表\n\n");
printf(" NN: 重新初始化列表\n\n");
printf("I+数字: 插入新节点\n\n");
printf("P+数字: 打印单个节点\n\n");
printf("D+数字: 删除单个节点\n\n");
printf("----------------------------\n\n");
return;
}
bool LinListInsert(LinkNode *&L, int i, student e)
{
int j = 0;
LinkNode *p = L, *s;
if (i <= 0)
return false; //i错误返回假
while (j < i - 1 && p != NULL) //查找第i-1个结点p
{
j++;
p = p->next;
}
if (p == NULL) //未找到位序为i-1的结点
return false;
else //找到位序为i-1的结点*p
{
s = (LinkNode *)malloc(sizeof(LinkNode));//创建新结点*s
s->data = (student *)malloc(sizeof(student));
strcpy(s->data->id, e.id);
strcpy(s->data->name, e.name);
strcpy(s->data->age, strcat(e.age, "\n"));
s->next = p->next; //将s结点插入到结点p之后
p->next = s;
return true;
}
if (flag_2)
{
printf("成功插入节点,当前节点列表为:\n\n");
DisplayLinList(L);
}
}
bool PrintLinList(LinkNode *L, int i)
{
int j = 0;
LinkNode *p = L->next;
if (i <= 0)
return false; //i错误返回假
while (j < i - 1 && p != NULL) //查找第i-1个结点p
{
j++;
p = p->next;
}
if (p == NULL) //未找到位序为i-1的结点
return false;
else //找到位序为i-1的结点*p
{
printf("\n%s, %s, %s\n", p->data->id, p->data->name, p->data->age);
return true;
}
}
int LinkedListMain(void)
{
student insert_elem;
int input_t;
char input_o;
LinListInstr();
InitLinList(L);
LinListGetInsert(L);
printf("\n请输入指令:");
scanf(" %c%d", &input_o, &input_t);
if (input_o == 'I')
{
printf("\n请输入待插入项: ");
scanf("%s %s %s", insert_elem.id, insert_elem.name, insert_elem.age);
// printf("%s, %s, %s, %c, %d\n", insert_elem.id, insert_elem.name, insert_elem.age, input_o, input_t);
}
while (input_o != 'Q')
{
switch (input_o)
{
case 'P':
PrintLinList(L, input_t);
break;
case 'D':
LinListDelete(L, input_t);
break;
case 'I':
LinListInsert(L, input_t, insert_elem);
break;
case 'R':
DestroyLinList(L);
break;
case 'E':
EmptyLinList(L);
break;
case 'L':
LinListLength(L);
break;
case 'S':
DisplayLinList(L);
break;
case 'T':
LinListInstr();
break;
case 'N':
InitLinList(L);
flag_2 = false;
LinListGetInsert(L);
flag_2 = true;
break;
default:
printf("指令有误,请重新输入。\n");
break;
}
printf("\n请输入指令:");
scanf(" %c%d", &input_o, &input_t);
if (input_o == 'I')
{
printf("\n请输入待插入项: ");
scanf("%s %s %s", insert_elem.id, insert_elem.name, insert_elem.age);
// printf("%s, %s, %s, %c, %d\n", insert_elem.id, insert_elem.name, insert_elem.age, input_o, input_t);
}
}
return 0;
}
- main() 函数:
#include "head.h"
void main(void)
{
char choice;
printf("请选择存储模式(S/L/Q):");
scanf("%c", &choice);
while (choice != 'Q')
{
switch (choice)
{
case 'S':
SqListMain();
break;
case 'L':
LinkedListMain();
break;
default:
printf("输入有误,请重新输入: \n");
break;
}
printf("请选择存储模式(S/L/Q):");
scanf("%c", &choice);
}
return;
}
data.txt 文件:
10225048,张三,24
10225132,李四,22
10225027,王五,24
10225213,赵六,25
10225197,欧阳奋强,23
10225059,孙八,24
10225083,余久,23
10225112,张唯一,24
总结:
-
fscanf()函数的使用
原型:int fscanf(FILE*stream,constchar*format,[argument...]);
头文件:<stdio.h>
功能:从一个流中执行格式化输入,fscanf遇到空格和换行时结束。这与fgets有区别,fgets遇到空格不结束。#include <stdio.h> #include <stdlib.h> int main() { char str1[10], str2[10], str3[10]; int year; FILE * fp; fp = fopen ("file.txt", "w+"); fputs("We are in 2014", fp); rewind(fp); fscanf(fp, "%s %s %s %d", str1, str2, str3, &year); printf("Read String1 |%s|\n", str1 ); printf("Read String2 |%s|\n", str2 ); printf("Read String3 |%s|\n", str3 ); printf("Read Integer |%d|\n", year ); fclose(fp); return(0); }
-
fgets()函数的使用
原型:char *fgets(char *buf, int bufsize, FILE *stream);
头文件:<string.h>
功能:从文件流读取一行,送到缓冲区。
fgets(e_oneline, 1024, fp);
-
strcpy()函数的使用
原型:char *strcpy(char* dest, const char *src);
头文件:<string.h> <stdio.h>
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间。strcpy(insert_elem.id, strtok(e_oneline, ",")); strcpy(insert_elem.name, strtok(NULL, ",")); strcpy(insert_elem.age, strtok(NULL, ","));
-
strtok()函数的使用
原型:char *strtok(char s[], const char *delim);
头文件:<string.h>
功能:分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。strcpy(insert_elem.id, strtok(e_oneline, ",")); strcpy(insert_elem.name, strtok(NULL, ",")); strcpy(insert_elem.age, strtok(NULL, ","));
-
memcpy()函数的使用
原型:void *memcpy(void *dest, const void *src, size_t n);
头文件:c:<string.h>; c++:<cstring>
功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。memcpy(insert_elem.id, temp, strlen(temp) + 1); memcpy(insert_elem.name, temp, strlen(temp) + 1); memcpy(insert_elem.age, temp, strlen(temp) + 1);
-
strcat()函数的使用
原型:extern char *strcat(char *dest, const char *src);
头文件:c: <string.h>;c++: <cstring>
功能:把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除dest原来末尾的“\0”)。要保证dest足够长,以容纳被复制进来的src,src中原有的字符不变,返回指向dest的指针。
strcpy(L->element[i].age, strcat(e.age, "\n"));
-
feof()函数和文件的使用
原型:int feof(FILE *stream);
头文件:<stdio.h>
功能:检测流上的文件结束符, 如果文件结束,则返回非0值,否则返回0值,文件结束符只能被clearerr()清除。bool SqListGetInsert(SqList *&L) { FILE *fp = NULL; student insert_elem; char e_oneline[1024], *temp; if ((fp = fopen("data.txt", "r")) == NULL) { printf("error!\n"); return false; } int i = 1; while (!feof(fp) && i < ORIGINA_DATA_NUM + 1) { fgets(e_oneline, 1024, fp); strcpy(insert_elem.id, strtok(e_oneline, ",")); strcpy(insert_elem.name, strtok(NULL, ",")); strcpy(insert_elem.age, strtok(NULL, ",")); /* memcpy(insert_elem.id, temp, strlen(temp) + 1); memcpy(insert_elem.name, temp, strlen(temp) + 1); memcpy(insert_elem.age, temp, strlen(temp) + 1); */ SqListInsert(L, i, insert_elem); i++; } fclose(fp); printf("\n初始化成功,当前节点列表为:\n\n"); DisplaySqList(L); flag_1 = true; return true; }
-
实验过程中出现的错误
将 strcpy(L->element[i].id, e.id); 写为 L->element[i].id = e.id;
错误原因:L->element[i].id 为一个已经定义好的数组,无法再为其重新定义,只可以为其赋值。L->element[i].id = e.id; L->element[i].name = e.name; L->element[i].age =e.age;
正确代码如下:
没有为结构体内部的结构体型变量分配空间:strcpy(L->element[i].id, e.id); strcpy(L->element[i].name, e.name); strcpy(L->element[i].age, strcat(e.age, "\n"));
错误原因:L->data时student型的结构体变量,虽然结构体student在定义时已经为id, name, age分配了空间,但是L->data仍然没有分配空间,需要为其重新分配。void InitLinList(LinkNode *&L) { L = (LinkNode *)malloc(sizeof(LinkNode)); L->next = NULL; }
正确代码如下:void InitLinList(LinkNode *&L) { L = (LinkNode *)malloc(sizeof(LinkNode)); L->data = (student *)malloc(sizeof(student)); L->next = NULL; }