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

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

   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[]; //伸缩型数组成员

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 * ) //对应的函数指针

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


相关文章
|
5月前
|
存储 C++
C primer plus 学习笔记 第17章 高级数据表示
C primer plus 学习笔记 第17章 高级数据表示
|
存储 数据处理 Python
Python基础知识详解:数据类型、对象结构、运算符完整分析
Python基础知识详解:数据类型、对象结构、运算符完整分析
147 1
|
机器学习/深度学习 搜索推荐 算法
编程艺术 - 第二章 、俩个字符串是否包含问题以及扩展
编程艺术 - 第二章 、俩个字符串是否包含问题以及扩展
69 0
|
存储 C语言
《C和指针》读书笔记(第十章 结构和联合)(下)
《C和指针》读书笔记(第十章 结构和联合)(下)
|
存储 C语言 C++
《C和指针》读书笔记(第十章 结构和联合)(上)
《C和指针》读书笔记(第十章 结构和联合)(上)
|
存储 算法 C#
C#面向对象程序设计课程实验三:实验名称:C#数组和集合
C#面向对象程序设计课程实验三:实验名称:C#数组和集合
C#面向对象程序设计课程实验三:实验名称:C#数组和集合
理解 Delphi 的类(一) - 从结构/记录谈起
理解 Delphi 的类(一) - 从结构/记录谈起
123 0
理解 Delphi 的类(一) - 从结构/记录谈起
|
存储 机器学习/深度学习 前端开发
带你读书之“红宝书”:第三章 语法基础(中)之 数据类型中部分Number类型①
带你读书之“红宝书”:第三章 语法基础(中)之 数据类型中部分Number类型①
77 0
带你读书之“红宝书”:第三章 语法基础(中)之 数据类型中部分Number类型①
|
存储 JavaScript 前端开发
带你读书之“红宝书”:第三章 语法基础(中)之 数据类型中部分Number类型②
带你读书之“红宝书”:第三章 语法基础(中)之 数据类型中部分Number类型②
94 0
带你读书之“红宝书”:第三章 语法基础(中)之 数据类型中部分Number类型②
|
存储 Java Windows
Java程序设计基础笔记 • 【第2章 变量与数据类型】
本章目录 2.1 变量 2.1.1 变量的概念 2.1.2 变量的使用 2.1.3 实践练习 2.2 数据类型 2.2.1 数据类型的种类 2.2.2 Java中的基本数据类型 1、整数类型 2、浮点类型 3、字符类型和布尔类型 2.2.3 实践练习 2.3 控制台的输入和输出 2.3.1 控制台的输入 2.3.2 控制台的输出 2.3.3 实践练习 2.4 调试 2.4.1 程序调试概述 2.4.2 实践练习 总结:
237 0
Java程序设计基础笔记 • 【第2章 变量与数据类型】