C primer plus 学习笔记 第14章 结构和其他数据形式
  TEZNKK3IfmPf 2023年11月12日 18 0


C primer plus 学习笔记 第14章  结构和其他数据形式

 


 

 14.1 示例问题:创建图书目录

一本书有多种信息,书名,作者,页数,价格等等,这些信息有的是字符串,有的是浮点数。

需要一种既有字符串,又有浮点数的数据形式————C结构。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
char * s_gets(char * st, int n);
#define MAXTITL 41
#define MAXAUTL 31
struct book { // 结构模板,标记是book
char title[MAXTITL];
char author[MAXAUTL];
float value;
};

int main(void)
{
struct book library; //声明struct book 类型变量 library
printf("Please enter the book title.\n");
s_gets(library.title, MAXTITL);
printf("Now enter the author.\n");
s_gets(library.author, MAXAUTL);
printf("Now enter the value.\n");
scanf("%f", &library.value);
printf("%s by %s: $%.2f\n", library.title, library.author, library.value);
printf("%s: \"%s\"($%.2f)\n", library.author, library.title, library.value);
printf("Done.\n");

return 0;
}

char * s_gets(char * st, int n)
{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n');//查找换行符
if (find)
*find = '\0'; //将换行符换成'\0'
else
while (getchar() != '\n') //处理输入行剩余的字符
continue;
}
return ret_val;
}

 

14.2 建立结构声明

结构声明(structure declaration)描述一个结构的组织布局,声明类似:

struct book {            
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

14.3 定义结构变量

程序中关键结构变量:

struct book library;

编译器在这里创建一个结构变量library,为其分配内存空间。

14.3.1 初始化结构

和初始化数组类似:

struct book library = { "The ...", "Renee Vivotte", 1.95};

14.3.2 访问结构成员

使用结构成员运算符 . 来访问结构中的成员。如:用library.value访问library的value

14.3.3 结构的初始化器

C99和C11为结构提供了指定初始化器(designated initializer),语法和数组的指定初始化器类似。

struct book surprise = { .value = 10.99};

14.4 结构数组

同样是那个图书问题,一本书用结构可以解决。

如果我们有很多本图书,就可以用结构数组了。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
char * s_gets(char *st, int n);
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBOOKS 100
#define _CRT_SECURE_NO_WARNINGS

struct book { // 结构模板,标记是book
char title[MAXTITL];
char author[MAXAUTL];
float value;
};

int main(void)
{
struct book library[MAXBOOKS]; //声明struct book 类型变量 library
int count = 0;
int index;

printf("Please enter the book title.\n");
printf("Enter at the start of a line to stop.\n");
while (count < MAXBOOKS && s_gets(library[count].title, MAXTITL) != NULL
&& library[count].title[0] != '\0')
{
printf("Now enter the anthor.\n");
s_gets(library[count].author, MAXAUTL);
printf("Now enter the value.\n");
scanf("%f", &library[count++].value);
while (getchar() != '\n')
continue;
if (count < MAXBOOKS)
printf("Enter the next title.\n");
}
if (count >0)
{
printf("Here is the list of your books:\n");
for (index = 0; index < count; index++)
printf("%s by %s: $%.2f\n", library[index].title,
library[index].author, library[index].value);
}
else
printf("No books?\n");

return 0;
}

char * s_gets(char * st, int n)
{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n');//查找换行符
if (find)
*find = '\0'; //将换行符换成'\0'
else
while (getchar() != '\n') //处理输入行剩余的字符
continue;
}
return ret_val;
}

 

14.4.1 声明结构数组

和其他类型的数组类似

int a[100];

struct book library[MAXBOOK]; //这里只是把int 类型换成struct book类型。

14.4.2 标识结构数组的成员

在结构名后面使用点.运算符

library[0].balue

14.4.3 程序讨论

 

14.5 嵌套结构

结构内包含另一个结构。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define LEN 20
const char * msgs[5] =
{
" Thank you for the wonderful evening, ",
"You certainly prove that a ",
"is a special kind of guy. We must get together",
"over a delicious ",
" and have a few laughs"
};
struct names {
char first[LEN];
char last[LEN];
};

struct guy {
struct names handle; //嵌套结构,结构里包含另一个结构
char favfood[LEN];
char job[LEN];
float income;
};

int main(void)
{
struct guy fellow = {
{"Ewen", "Villard"},
"grilled salmon",
"personality coach",
68112.00
};
printf("Dear %s,\n\n", fellow.handle.first); //使用嵌套结构,先使用.得到name,再.得到first
printf("%s%s.\n", msgs[0], fellow.handle.first);
printf("%s%s\n", msgs[1], fellow.job);
printf("%s\n", msgs[2]);
printf("%s%s%s", msgs[3], fellow.favfood, msgs[4]);
if (fellow.income > 150000.0)
puts("!!");
else if (fellow.income > 75000.0)
puts("!");
else
puts(".");
printf("\n%40s%s\n", " ", "See you soon,");
printf("%40s%s\n", " ", "Shalala");

return 0;
}

14.6 指向结构的指针

/*friends.c --使用指向结构的指针*/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define LEN 20

struct names {
char first[LEN];
char last[LEN];
};

struct guy {
struct names handle;
char favfood[LEN];
char job[LEN];
float income;
};

int main(void)
{
struct guy fellow[2] ={
{{"Ewen", "Villard"},
"grilled salmon",
"personality coach",
68112.00
},
{{"Rodney","Swillbelly"},
"tripe",
"tabloid editor",
432400.00
}
};
struct guy * him; //指向结构的指针


printf("address #1:%p #2: %p\n",&fellow[0],&fellow[1]);
him = &fellow[0];
printf("pointer#1:%p #2: %p\n", him, him + 1);
printf("him->income is $%.2f: (*him).income is $%.2f\n",
him->income, (*him).income);
him++;
printf("him->favfood is %s: him->handler.last is %s\n",
him->favfood, him->handle.last);
return 0;

}

 

14.6.1 声明和初始化结构指针

声明结构指针://和其他指针类似

struct guy * him;

barney是一个guy类型的结构:可以这样给指针赋值:

him = &barney;

14.6.2 用指针访问成员

方法1:指针->成员    如:him->income

方法2:(*指针).成员  如:(*him).income

 

14.7 向函数传递结构的信息

14.7.1 传递结构成员

传递结构成员给函数和传递普通变量给函数并没有什么不同。

#include<stdio.h>
#define FUNDLEN 50

struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};

double sum(double, double);

int main(void)
{
struct funds stan = {
"Garlic--Melon Bank",
4032.27,
"Lucky's Savings and Loan",
8543.94
};

printf("Stan has a total of $%.2f.\n",sum(stan.bankfund,stan.savefund)); //
return 0;
}
double sum(double x, double y)
{
return (x + y);
}

 

14.7.2 传递结构的地址 (结构指针做参数)

#include<stdio.h>
#define FUNDLEN 50

struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};

double sum(const struct funds *); //

int main(void)
{
struct funds stan = {
"Garlic--Melon Bank",
4032.27,
"Lucky's Savings and Loan",
8543.94
};

printf("Stan has a total of $%.2f.\n", sum(&stan)); //
return 0;
}
double sum(const struct funds * money) //
{
return (money->bankfund + money->savefund);
}

 

14.7.3 传递结构

传递结构是传值,函数将创建一个结构副本,然后把实际参数的值给这个副本,函数中的操作都是对副本进行的。

#include<stdio.h>
#define FUNDLEN 50

struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};

double sum( struct funds moolah);

int main(void)
{
struct funds stan = {
"Garlic--Melon Bank",
4032.27,
"Lucky's Savings and Loan",
8543.94
};

printf("Stan has a total of $%.2f.\n", sum(stan));
return 0;
}
double sum( struct funds moolah) //函数创建一个副本moolah,然后对副本进行操作(不会改变实际参数stan)
{
return( moolah.bankfund + moolah.savefund);
}

 

14.7.4 其他结构特性

一个结构可以赋值给另一个结构(数组不行)。

神奇的是,如果结构的成员是数组,结构间的赋值仍然可以。

14.7.5 结构和结构指针的选择

通常用结构指针作为函数的参数,这样效率较高。如需要防止原始数据被修改,使用const限定符。

14.7.6 结构中的字符数组和字符指针

字符数组比较简单。

字符指针由于只是给出一个地址,但并未分配内存,可能会存到意外的地方。

14.7.7 结构、指针和malloc()

使用malloc()分配内存并使用指针存储该地址。

14.7.8 复合字面量和结构(C99)

14.7.9 伸缩型数组成员(C99)

1.伸缩型数组成员必须是结构的最后一个成员

2.结构必须至少有一个成员

3.伸缩数组的声明类似于普通数组,只是它的方括号内是空的。

例子:

struct flex

{

int count;

double average;

double scores[]; //伸缩型数组成员

};

声明一个 struct flex类型的变量后不能使用scores,因为还没给它分配存储空间。

通常使用方法是声明一个struct flex类型的指针,然后用malloc()给它分配存储空间。如:

struct flex *pf;

pf = malloc(sizeof(struct flex) + 5* sizeof(double) );

14.7.10 匿名结构(C11)

C11中,可以用嵌套的匿名结构进行简化。//但是嵌套结构用处不大

struct person

{

  int id;

struct { char first[20]; char last[20];}; //匿名结构

}

访问first时,只需将其看出是person的成员

person ted ; ...

ted.first;

 

14.7.11 使用结构数组的函数

//把结构数组传递给函数
#include<stdio.h>
#define FUNDLEN 50
#define N 2

struct funds {
char bank[FUNDLEN];
double bankfund;
char save[FUNDLEN];
double savefund;
};

double sum(const struct funds mooey[], int n); //传入结构数组的函数

int main(void)
{
struct funds jones[N] = {
{
"Garlic--Melon Bank",
4032.27,
"Lucky's Savings and Loan",
8543.94
},
{
"Honest Jack's Bank",
3620.88,
"Party Time Savings",
3802.91
}
};

printf("The joneses have a total of $%.2f.\n", sum(jones,N) ); *//使用sum函数
return 0;
}
double sum(const struct funds money[],int n)
{
double total;
int i;
for ( i = 0, total = 0; i < n; i++)
total += money[i].bankfund + money[i].savefund;
return total;
}

 

14.8 把结构内容保存到文件中

("a+b")模式打开文件,a+可以在文件末尾添加,b 使用二进制文件格式,

使用fread()和fwrite()进行读写。

//在文件中保存结构中的内容
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXTITL 40
#define MAXAULT 40
#define MAXBKS 10
char * s_gets(char * st, int n);
struct book {
char title[MAXTITL];
char author[MAXAULT];
float value;
};

int main(void)
{
struct book library[MAXBKS];
int count = 0;
int index, filecount;
FILE * pbooks;
int size = sizeof(struct book);
if ((pbooks = fopen("book.dat", "a+b")) == NULL)
{
fputs("Can't open book.dat file\n", stderr);
exit(1);
}
rewind(pbooks);
while (count<MAXBKS && fread(&library[count],size,1,pbooks) == 1)
{
if (count == 0)
puts("Current contents of book.dat:");
printf("%s by %s $%.2f\n", library[count].title,
library[count].author, library[count].value);
count++;
}
filecount = count;
if (count == MAXBKS)
{
fputs("The book.dat file is full.", stderr);
exit(2);
}
puts("Please add new book titles.");
puts("Press [enter] at the start of a line to stop.");
while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL
&& library[count].title[0] != '\0')
{
puts("Now enter the author.");
s_gets(library[count].author, MAXAULT);
puts("Now enter the value.");
scanf("%f", &library[count++].value);
while (getchar() != '\n')
continue;
if (count < MAXBKS)
puts("Enter the next title.");
}
if (count > 0)
{
puts("Here is the list of your books:");
for (index = 0; index < count; index++)
printf("%s by %s:$%.2f\n", library[index].title,
library[index].author, library[index].value);
fwrite(&library[filecount], size, count - filecount, pbooks);
}
else
puts("No books.\n");
puts("Bye.\n");

return 0;

}


char * s_gets(char * st, int n)
{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n');//查找换行符
if (find)
*find = '\0'; //将换行符换成'\0'
else
while (getchar() != '\n') //处理输入行剩余的字符
continue;
}
return ret_val;
}

 

 

 

14.9 链式结构

 

10.10 联合简介

联合(union)是一种数据类型,能在同一个内存空间存储不同的数据类型。

定义联合:

union hold {

 int digit;

 double bigfl;

 char letter;

}

hold的联合体可以存储一个int 或一个double或一个char,同一时刻只能三个中的一个。

 

14.11 枚举类型

(enumerated type)

可以声明符号名称代替整型常量

enum spectrum {red, orange, yellow, green, blue, violet};

 

14.12 typedef简介(别名)

typedef char * STRING

STRING name , sign ;// 等价char * name , * sign;

 

14.13 其他复杂的声明

 

14.14 函数和指针

函数也有地址,指向函数的指针中存储着函数代码的起始位置。

函数指针需要指明函数的返回类型和参数类型:

void ToUpper(char *) //函数

void (*pf) (char * ) //对应的函数指针

声明了函数指针后,可以把类型匹配的函数地址(函数名)赋值给他。

 

 

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   23天前   35   0   0 C++
  TEZNKK3IfmPf   23天前   24   0   0 指针C++
  TEZNKK3IfmPf   2024年05月31日   24   0   0 算法C++
TEZNKK3IfmPf