C语言总结(第9章 用户自己建立数据类型)

简介: 书上典型例题总结:示例问题:创建图书目录 建立结构声明 访问结构成员 指向结构的指针 关键概念 本章小结 第九章目录 第九章课后题答案

书上典型例题总结:


如何去定义一个结构体数组:

#include<stdio.h>

#include<string.h>

struct Person

{

   char name[20];

   int count;

}leader[3]={"Li",0,"Zhang",0,"Sun",0};

int main()

{

   int i,j;

   char leader_name[20];

   for (i=1;i<=10;i++)

   {

       scanf("%s",leader_name);

       for(j=0;i<3;i++)

       if(strcmp(leader_name,leader[j].name)==0)leader[j].count++;

 

   }

printf("\nResult:\n");

for(i=0;i<3;i++)

   printf("%5s:%d\n",leader[i].name,leader[i].count);

return 0;

}

指向结构体变量的指针:

#include<stdio.h>

#include<string.h>

int main()

{

   struct Student

   {

       long num;

       char name[20];

       char sex;

       float score;

   };

struct Student_stu_1;

struct Student*p;

p=stu&_1;            //p指向stu_1

stu_1.num=10101;

strcpy(stu_1.name,"Li Lin");

stu_1.sex='M';

stu_1.score=89.5;

printf("No.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n");

       stu_1.num,stu_1.name,stu_1.sex,stu_1.score);

printf("No.:%ld\nname:%s\nsex:%c\nscore:%5.1f\n");

      (*p).num,(*p).name,(*p).sex,(*p).score);    //(*p)表示p指向的结构体变量,(*p).num表示p所指向的结构体变量中的成员num。注意*两侧的括号不可省,因为成员运算符“.”优先于“*”运算符

return 0;

}

如果p指向一个结构体变量stu,以下三种用法等价


(1)stu.成员名(如stu.num);


(2)(*p).成员名(如(*p).num);


(3)p->成员名(如p->num)。


306页例9.7:


学生成绩管理系统


#include<stdio.h>

#include<stdlib.h>

#include<stdlib.h>

#include<string.h>

struct Student{   //每个学生对应一个结构体

char ID[20];//学号

char Name[10];//姓名

float Mark1;//语文成绩

float Mark2;//数学成绩    //四个变量

float Mark3;//英语成绩

float Mark4;//计算机成绩

float All; //总分

float Average;//平均成绩

}students[1000];

int num=0; //计数器

void Copy(struct Student *arr,int i,int j)

{

strcpy(arr[i].ID,arr[j].ID);  //strcpy()函数的简介:

        是将一个字符串复制到另一块空间地址中 的函数,‘\0’是停止拷贝的终止条件,

         也复制到目标空间。下面是库中的strcpy()函数声明:

strcpy(arr[i].Name,arr[j].Name);

arr[i].Mark1 = arr[j].Mark1;

arr[i].Mark2 = arr[j].Mark2;

arr[i].Mark3 = arr[j].Mark3;

arr[i].Mark4 = arr[j].Mark4;

arr[i].All = arr[j].All;

arr[i].Average = arr[j].Average;

}

int Student_SearchByName(char name[])//通过姓名来检索学生

{

    int i;

    for (i=0;i<num;i++)

    {

        if (strcmp(students[i].Name,name)==0)  //通过strcmp函数来对比学生姓名,找到返回在数组的位置

        {

             return i;

      }

    }

    return -1;    //未找到返回 -1

}

int Student_SearchByIndex(char id[])//通过学号来检索学生信息

{

    int i;

    for (i=0;i<num;i++)

    {

        if (strcmp(students[i].ID,id)==0)  //通过strcmp函数来对比学生id,找到返回位置

        {

             return i;

        }  

    }

    return -1;   //未找到返回 -1

}

void Student_DisplaySingle(int index)//输出表头

{

    printf("%10s%10s%8s%8s%8s%10s\n","学号","姓名","语文","数学","英语","计算机","总成绩","平均成绩");

    printf("-------------------------------------------------------------\n");

    printf("%10s%10s%8.2f%8.2f%8.2f%8.2f%10.2f%10.2f\n",students[index].ID,students[index].Name,

             students[index].Mark1,students[index].Mark2,students[index].Mark3,students[index].Mark4,students[index].All,students[index].Average);

}

void inputt()//利用循环录入学生信息

{

    while(1)

    {

        printf("请输入学号:");

        scanf("%s",&students[num].ID);

        getchar();

        printf("请输入姓名:");

        scanf("%s",&students[num].Name);

        getchar();

        printf("请输入成绩:");

        scanf("%f",&students[num].Mark1);

        getchar();

        printf("请输入成绩:");

        scanf("%f",&students[num].Mark2);

        getchar();

        printf("请输入成绩:");

        scanf("%f",&students[num].Mark3);

        getchar();

        printf("请输入成绩:");

        scanf("%f",&students[num].Mark4);   //依次输入各项数据

        getchar();

        students[num].All=students[num].Mark1+students[num].Mark2+students[num].Mark3+students[num].Mark4;    //输完数据后自动计算总成绩与平均成绩

        students[num].Average=(students[num].Mark1+students[num].Mark2+students[num].Mark3+students[num].Mark4)/4;

        if(Student_SearchByIndex(students[num].ID) == -1)

        {

         num++;  //移向下一个位置

  }

  else

  {

   printf("学号重复,输入数据无效 !!!\n");

  }

 

   printf("是否继续?(y/n)");

        if (getchar()=='n')

        {

             break;

        }

    }

}

void modify()//修改成绩

{

  while(1)

    {

        char id[20];

        int index;

        printf("请输入要修改的学生的学号:");

        scanf("%s",&id);

        getchar();

        index=Student_SearchByIndex(id);  //调用搜查id函数,根据其返回值确定位置

        if (index==-1)

        {

             printf("学生不存在!\n");

        }

        else

        {

             printf("你要修改的学生信息为:\n");

             Student_DisplaySingle(index);

             printf("-- 请输入新值--\n");

             printf("请输入学号:");

             scanf("%s",&students[index].ID);

             getchar();

             printf("请输入姓名:");

             scanf("%s",&students[index].Name);

             getchar();

             printf("请输入语文成绩:");

             scanf("%f",&students[index].Mark1);

     getchar();

             printf("请输入数学成绩:");

             scanf("%f",&students[index].Mark2);

             getchar();

             printf("请输入英语成绩:");

             scanf("%f",&students[index].Mark3);

             getchar();

             printf("请输入计算机成绩:");

             scanf("%f",&students[index].Mark4);  //重新录入一套新的数据替代

             getchar();

             students[index].All=students[index].Mark1+students[index].Mark2+students[index].Mark3+students[index].Mark4;

          students[index].Average=(students[index].Mark1+students[index].Mark2+students[index].Mark3+students[index].Mark4)/4;  

        }

        printf("是否继续?(y/n)");

        if (getchar()=='n')

        {

             break;

        }

    }

}

void deletee()//删除学生信息

{

  int i;

    while(1)

    {

        char id[20];

        int index;

        printf("请输入要删除的学生的学号:");

        scanf("%s",&id);

        getchar();

        index=Student_SearchByIndex(id);   //调用搜查id函数,根据其返回值确定位置

        if (index==-1)

        {

             printf("学生不存在!\n");

        }

        else

        {

             printf("你要删除的学生信息为:\n");

             Student_DisplaySingle(index);

             printf("是否真的要删除?(y/n)");

             if (getchar()=='y')

             {

                  for (i=index;i<num-1;i++)

                  {

                      Copy(students,i,i+1);

                      //students[i]=students[i+1];    //把后边的对象都向前移动

                  }

                  num--;

             }

            getchar();

        }

        printf("是否继续?(y/n)");

        if (getchar()=='n')

        {

             break;

        }

    }

}

void display()//打印已录入的学生信息

{

 int a;

    printf("%10s%10s%8s%8s%8s%8s%10s%10s\n","学号","姓名","语文","数学","英语","计算机","总成绩","平均成绩");

    printf("-------------------------------------------------------------\n");

    for (a=0;a<num;a++)

    {

        printf("%10s%10s%8.2f%8.2f%8.2f%8.2f%10.2f%10.2f\n",students[a].ID,students[a].Name,

             students[a].Mark1,students[a].Mark2,students[a].Mark3,students[a].Mark4,students[a].All,students[a].Average);

    }

}

void insert()//指定位置插入学生信息

{

 int a,b,c;

 printf("请输入你要插入的位置");

 scanf("%d",&a);

 if(a>num) {

 printf("输入的位置有误,请重新输入,当前共%d条数据\n",num);

 scanf("%d",&a);}

     b=num-1;

     for(;b>=a-1;b--)

     {

      //strcpy(students[b+1].ID,students[b].ID);

      //strcpy(students[b+1].Name,students[b].Name);

      //students[b+1].Mark1=students[b].Mark1;

      //students[b+1].Mark2=students[b].Mark2;

      //students[b+1].Mark3=students[b].Mark3;

      //students[b+1].Mark4=students[b].Mark4;

      //students[b+1].All=students[b].All;

      //students[b+1].Average=students[b].Average;  

  Copy(students,b+1,b); //根据其输入的位置,将其及以后的数据向后移动一个位置

   

  }

  num++;

        printf("请输入学号:");

        scanf("%s",&students[a-1].ID);

        getchar();

        printf("请输入姓名:");

        scanf("%s",&students[a-1].Name);

        getchar();

        printf("请输入语文成绩:");

        scanf("%f",&students[a-1].Mark1);

        getchar();

        printf("请输入数学成绩:");

        scanf("%f",&students[a-1].Mark2);

        getchar();

        printf("请输入英语成绩:");

        scanf("%f",&students[a-1].Mark3);

        getchar();

        printf("请输入计算机成绩:");

        scanf("%f",&students[a-1].Mark4);  //输入新数据

        getchar();  

        students[a-1].All=students[a-1].Mark1+students[a-1].Mark2+students[a-1].Mark3+students[a-1].Mark4;

        students[a-1].Average=(students[a-1].Mark1+students[a-1].Mark2+students[a-1].Mark3+students[a-1].Mark4)/4;

}

void search()//查询学生信息

{

 while(1)

    {

        char name[20];

        int index;

        printf("请输入要查询的学生的姓名:");

        scanf("%s",&name);

        getchar();

        index=Student_SearchByName(name);   //调用搜查name函数,根据其返回值确定位置

        if (index==-1)

        {

             printf("学生不存在!\n");

        }

        else

        {

             printf("你要查询的学生信息为:\n");

             Student_DisplaySingle(index);

        }

        printf("是否继续?(y/n)");

        if (getchar()=='n')

        {

             break;

        }

    }

}

voidsort()//根据平均分排序

(此时注意按照题目要求应该排序两个)

{

 int i,j;

 //struct students tmp;

    for (i=0;i<num;i++)

    {

     students[i].Average=(students[i].Mark1+students[i].Mark2+students[i].Mark3+students[i].Mark4)/4;

    }

    for (i=0;i<num;i++)

    {

        for (j=1;j<num-i;j++)

        {

             if (students[j-1].Average<students[j].Average)

             {

               

      Copy(students,num,j-1);

      Copy(students,j-1,j);

      Copy(students,j,num);

      //tmp=students[j-1];

                  //students[j-1]=students[j];

                  //students[j]=tmp;      //冒泡排序

           }  

        }

    }

    int a;

    printf("%10s%10s%8s%8s%8s%10s\n","学号","姓名","语文","数学","英语","计算机","总成绩","平均成绩");

    printf("-------------------------------------------------------------\n");

    for (a=0;a<num;a++)

    {

        printf("%10s%10s%8.2f%8.2f%8.2f%8.2f%10.2f%10.2f\n",students[a].ID,students[a].Name,

             students[a].Mark1,students[a].Mark2,students[a].Mark3,students[a].Mark4,students[a].All,students[a].Average);

    }

}

void SearchLow()//搜索不及格的并输出

{

int a;

printf("           语文不及格的有%10s%10s%8s\n","学号","姓名","语文");

for(a=0;a<num;a++)

{

 if(students[a].Mark1<60)

 printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark1);    //从头搜索到尾,若小于60就输出

 }

 

printf("           数学不及格的有%10s%10s%8s\n","学号","姓名","数学");

for(a=0;a<num;a++)

{

 if(students[a].Mark2<60)

 printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark2);

 }

 

 printf("           英语不及格的有%10s%10s%8s\n","学号","姓名","英语");

for(a=0;a<num;a++)

{

 if(students[a].Mark3<60)

 printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark3);

 }

 

 printf("           计算机不及格的有%10s%10s%8s\n","学号","姓名","计算机");

for(a=0;a<num;a++)

{

 if(students[a].Mark4<60)

 printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark4);

 }

 system("pause");  //这个好像没作用

}

void SearchHigh()//搜索成绩最高者输出

{

int a;

int max ;

printf("           语文最高分为%10s%10s%8s\n","学号","姓名","语文");

max=students[0].Mark1;

for(a=1;a<num;a++)

{

 if(students[a].Mark1>max)

 max=students[a].Mark1;

}

for(a=0;a<num;a++)

{

 if(max==students[a].Mark1)

 printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark1);

}

printf("           数学最高分为%10s%10s%8s\n","学号","姓名","数学");

max=students[0].Mark2;

for(a=1;a<num;a++)

{

 if(students[a].Mark2>max)

 max=students[a].Mark2;

}

for(a=0;a<num;a++)

{

 if(max==students[a].Mark2)

 printf("%10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark2);

}

printf("           英语最高分为%10s%10s%8s\n","学号","姓名","英语");

max=students[0].Mark3;

for(a=1;a<num;a++)

{

 if(students[a].Mark3>max)

 max=students[a].Mark3;

}

for(a=0;a<num;a++)

{

 if(max==students[a].Mark3)

 printf("           %10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark3);

}

printf("           计算机最高分为%10s%10s%8s\n","学号","姓名","计算机");

max=students[0].Mark4;

for(a=1;a<num;a++)

{

 if(students[a].Mark4>max)

 max=students[a].Mark4;

}

for(a=0;a<num;a++)

{

 if(max==students[a].Mark4)

 printf("           %10s%10s%8.2f\n",students[a].Name,students[a].ID,students[a].Mark4);

}

 system("pause");

}

void Save()

{

FILE*fp = fopen("temp.txt","w+");

fprintf(fp,"%d\n",num);

for(int i = 0 ; i< num ;i++)

{

 fprintf(fp,"%s %s %f %f %f %f %f %f\n",students[i].ID,students[i].Name,students[i].Mark1,students[i].Mark2,students[i].Mark3,students[i].Mark4,students[i].All,students[i].Average);

}

fclose(fp);

}

void Load()

{

FILE*fp = fopen("temp.txt","r");

fscanf(fp,"%d",&num);

for(int i = 0 ; i< num ;i++)

{

 fscanf(fp,"%s %s %f %f %f %f %f %f\n",students[i].ID,students[i].Name,&students[i].Mark1,&students[i].Mark2,&students[i].Mark3,&students[i].Mark4,&students[i].All,&students[i].Average);

}

fclose(fp);

}

/*主程序*/

int main(){

int i;

while(1){

  Load();

  printf("\t\t\t\t\t-------- 学生成绩管理系统-------\n\n\n\n");     //菜单

        printf("\t\t\t\t\t1. 增加学生记录\n\n");

        printf("\t\t\t\t\t2. 修改学生记录\n\n");

        printf("\t\t\t\t\t3. 删除学生记录\n\n");

        printf("\t\t\t\t\t4. 插入学生记录\n\n");

        printf("\t\t\t\t\t5. 显示所有记录\n\n");

        printf("\t\t\t\t\t6. 查询学生记录\n\n");

        printf("\t\t\t\t\t7. 按平均成绩排序\n\n");

        printf("\t\t\t\t\t8. 输出各科目不及格学生\n\n");

        printf("\t\t\t\t\t9. 输出各科目最高分\n\n");

        printf("\t\t\t\t\t0. 退出\n\n\n");

        printf("请选择(0-9):");

   scanf("%d",&i);

  switch(i){

  case 1:inputt();break;

  case 2:modify();break;

   case 3:deletee();break;

   case 4:insert();break;

   case 5:display();break;

  case 6:search();break;

  case 7:sort();break;

  case 8:SearchLow();break;

  case 9:SearchHigh();break;

  case 0:exit(0);

  default:  ;

}

Save();

}

 return 0;

}

void Save() {

FILE *fp = fopen("temp.txt", "w+");

fprintf(fp, "%d\n", num);

for (int i = 0 ; i < num ; i++) {

 fprintf(fp, "%s %s %f %f %f %f %f %f\n", students[i].ID, students[i].Name, students[i].Mark1, students[i].Mark2,

         students[i].Mark3, students[i].Average1);

}

fclose(fp);

}

void Load() {

FILE *fp = fopen("temp.txt", "r");

fscanf(fp, "%d", &num);

for (int i = 0 ; i < num ; i++) {

 fscanf(fp, "%s %s %f %f %f %f %f %f\n", students[i].ID, students[i].Name, &students[i].Mark1, &students[i].Mark2,

        &students[i].Mark3, &students[i].Average1);

}

fclose(fp);

}

调试示例error09_1.cpp(结构)


输入一个正整数n(3≤n≤10),再输入n个雇员的信息,包括姓名、基本工资、浮动工资和支出,输出每人的姓名和实发工资,实发工资=基本工资+浮动工资-支出。


输入输出示例:括号内为说明


输入:


3 (n=3)


zhao 240 400 75


qian 360 120 50


zhou 560 0 80


输出:


zhao 实发工资: 565.00


qian 实发工资: 430.00


zhou 实发工资: 480.00


#include <stdio.h>

int main (void)

{

   int i, n;

     struct emp{

       char  name[10];

       double jbg;

       double fdg;

       double zc;

   } s[10];

   scanf("%d", &n);

for(i=0;i<n;i++)

scanf("%s%lf%lf%lf",s[i].name, &s[i].jbg,&s[i].fdg,&s[i].zc);

   for (i = 0; i < n; i++)

       printf ("%5s 实发工资:%7.2f\n", s[i].name, s[i].jbg + s[i].fdg - s[i].zc);

}


90002    时间换算(结构)


输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:


输入一个时间数值,再输入秒数 n,输出该时间再过 n 秒后的时间值,时间的表示形式为时:分:秒,超过 24 时从 0 时重新开始计时。


输入输出示例:括号内为说明


输入:


3    (repeat=3)


0:0:1


59    (秒数n=59)


11:59:40  


30    (秒数n=30)


23:59:40  


301    (秒数n=301)


输出:


time: 0:1:0    (0:0:01加上59秒的新时间)  


time: 12:0:10    (11:59:40加上30秒的新时间)


time: 0:4:41    (23:59:40加上301秒的新时间)


#include <stdio.h>


int main(void)


{

   int n;

   int repeat, ri;

   struct time{

       int hour, minute, second;

   }time;

   scanf("%d", &repeat);

   for(ri = 1; ri <= repeat; ri++){

       scanf("%d:%d:%d", &time.hour, &time.minute, &time.second);

       scanf("%d",&n);

time.second=time.second+n;

if(time.second>=60){

time.minute=time.minute+time.second/60;

time.second=time.second%60;

if(time.minute>=60){

time.hour=time.hour+time.minute/60;

time.minute=time.minute%60;

if(time.hour>=24)

time.hour=time.hour-24;

}

}

       printf("time: %d:%d:%d\n", time.hour, time.minute, time.second);

  }

}

90003    计算平均成绩(结构)


输入整数n(n<10),再输入n个学生的基本信息,包括序号、姓名和成绩,要求计算并输出他们的平均成绩(保留2位小数)。


输入输出示例:括号内为说明


输入:


3 (n=3)


1  zhang  70


2  wang  80


3  qian  90


输出:


average: 80.00

#include <stdio.h>

int main(void)

{

   int i, n;

   double average, sum;

   struct student{

       int num;

       char name[10];

       int score;

   }s[10];

   scanf("%d", &n);

sum=0;

for(i=0;i<n;i++){

scanf("%d%s%d",&s[i].num,s[i].name,&s[i].score);

sum+=s[i].score;

}

average=sum/n;

   printf("average: %.2f\n", average);

}

90004    计算两个复数之积(结构)


输入4个整数a1,b1,a2,b2,分别表示两个复数的实部与虚部,求两个复数之积(a1+b1i)*(a2+b2i),乘积的实部为:a1*a2-b1*b2,虚部为:a1*b2+a2*b1。


输入输出示例:括号内为说明


输入:


3 4 5 6


输出:


(3+4i) * (5+6i) = -9 + 38i

#include <stdio.h>

int main(void)

{

   struct complex{

       int real;

       int imag;

   }product, x, y;

   scanf("%d%d%d%d", &x.real, &x.imag, &y.real, &y.imag);

product.real=x.real*y.real-x.imag*y.imag;

product.imag=x.real*y.imag+x.imag*y.real;

   printf("(%d+%di) * (%d+%di) = %d + %di\n", x.real, x.imag, y.real, y.imag, product.real, product.imag);

}


示例问题:创建图书目录


Gwen Glenn要打印一份图书目录。她想打印每本书的各种信息:书名、


作者、出版社、版权日期、页数、册数和价格。其中的一些项目(如,书


名)可以储存在字符数组中,其他项目需要一个int数组或float数组。用 7 个


不同的数组分别记录每一项比较繁琐,尤其是 Gwen 还想创建多份列表:一


份按书名排序、一份按作者排序、一份按价格排序等。如果能把图书目录的


信息都包含在一个数组里更好,其中每个元素包含一本书的相关信息。


因此,Gwen需要一种即能包含字符串又能包含数字的数据形式,而且


还要保持各信息的独立。C结构就满足这种情况下的需求。我们通过一个示


例演示如何创建和使用数组。但是,示例进行了一些限制。第一,该程序示


例演示的书目只包含书名、作者和价格。第二,只有一本书的数目。当然,


别忘了这只是进行了限制,我们在后面将扩展该程序。请看程序清单14.1及


其输出,然后阅读后面的一些要点。


程序清单14.1 book.c程序


//* book.c -- 一本书的图书目录 */


#include <stdio.h>


#include <string.h>


char * s_gets(char * st, int n);


#define MAXTITL41 /* 书名的最大长度 + 1 */


#define MAXAUTL31 /* 作者姓名的最大长度 + 1*/


struct book { /* 结构模版:标记是 book */


char title[MAXTITL];


1007char author[MAXAUTL];


float value;


}; /* 结构模版结束 */


int main(void)


{

struct book library; /* 把 library 声明为一个 book 类型的变量 */

printf("Please enter the book title.\n");

s_gets(library.title, MAXTITL); /* 访问title部分*/

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;

}

1008char * 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) // 如果地址不是 NULL,

*find = '\0'; // 在此处放置一个空字符

else

while (getchar() != '\n')

continue; //处理输入行中剩余的字符

}

return ret_val;

}

我们使用前面章节中介绍的s_gets()函数去掉fgets()储存在字符串中的换


行符。下面是该例的一个运行示例:


Please enter the book title.


1009Chicken of the Andes


Now enter the author.


Disma Lapoult


Now enter the value.


29.99


Chicken of the Andes by Disma Lapoult: $29.99


Disma Lapoult: "Chicken of the Andes" ($29.99)


Done.


程序清单14.1中创建的结构有3部分,每个部分都称为成员(member)


或字段(


field)。这3部分中,一部分储存书名,一部分储存作者名,一部


分储存价格。下面是必须掌握的3个技巧:


为结构建立一个格式或样式;


声明一个适合该样式的变量;


访问结构变量的各个部分


建立结构声明


结构声明(


structure declaration)描述了一个结构的组织布局。声明类


似下面这样:


struct book {

char title[MAXTITL];

char author[MAXAUTL];

float value;

};


该声明描述了一个由两个字符数组和一个float类型变量组成的结构。该


声明并未创建实际的数据对象,只描述了该对象由什么组成。〔有时,我们


把结构声明称为模板,因为它勾勒出结构是如何储存数据的。如果读者知道


C++的模板,此模板非彼模板,C++中的模板更为强大。〕我们来分析一些


细节。首先是关键字 struct,它表明跟在其后的是一个结构,后面是一个可


选的标记(该例中是 book),稍后程序中可以使用该标记引用该结构。所


以,我们在后面的程序中可以这样声明:


struct book library;


这把library声明为一个使用book结构布局的结构变量。


在结构声明中,用一对花括号括起来的是结构成员列表。每个成员都用


自己的声明来描述。例如,title部分是一个内含MAXTITL个元素的char类型


数组。成员可以是任意一种C的数据类型,甚至可以是其他结构!右花括号


后面的分号是声明所必需的,表示结构布局定义结束。可以把这个声明放在


所有函数的外部(如本例所示),也可以放在一个函数定义的内部。如果把


结构声明置于一个函数的内部,它的标记就只限于该函数内部使用。如果把


结构声明置于函数的外部,那么该声明之后的所有函数都能使用它的标记。


1011例如,在程序的另一个函数中,可以这样声明:


struct book dickens;


这样,该函数便创建了一个结构变量dickens,该变量的结构布局是


book。


结构的标记名是可选的。但是以程序示例中的方式建立结构时(在一处


定义结构布局,在另一处定义实际的结构变量),必须使用标记。我们学完


如何定义结构变量后,再来看这一点。


访问结构成员


结构类似于一个“超级数组”,这个超级数组中,可以是一个元素为char


类型,下一个元素为forat类型,下一个元素为int数组。可以通过数组下标单


独访问数组中的各元素,那么,如何访问结构中的成员?使用结构成员运算


符——点(


.)访问结构中的成员。例如,library.value即访问library的value


部分。可以像使用任何float类型变量那样使用library.value。与此类似,可以


像使用字符数组那样使用 library.title。因此,程序清单 14.1 中的程序中有


s_gets(library.title, MAXTITL);和scanf("%f", &library.value);这样的代码。


本质上,.title、.author和.value的作用相当于book结构的下标。


注意,虽然library是一个结构,但是library.value是一个float类型的变


量,可以像使用其他 float 类型变量那样使用它。例如,scanf("%f",...)需要一


个 float 类型变量的地址,而&library.float正好符合要求。.比&的优先级高,


因此这个表达式和&(library.float)一样。


指向结构的指针


喜欢使用指针的人一定很高兴能使用指向结构的指针。至少有 4 个理由


可以解释为何要使用指向结构的指针。第一,就像指向数组的指针比数组本


身更容易操控(如,排序问题)一样,指向结构的指针通常比结构本身更容


易操控。第二,在一些早期的C实现中,结构不能作为参数传递给函数,但


是可以传递指向结构的指针。第三,即使能传递一个结构,传递指针通常更


有效率。第四,一些用于表示数据的结构中包含指向其他结构的指针。


下面的程序(程序清单14.4)演示了如何定义指向结构的指针和如何用


这样的指针访问结构的成员。


程序清单14.4 friends.c程序


/* friends.c -- 使用指向结构的指针 */

#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];

1031float 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]; /* 告诉编译器该指针指向何处 */

1032printf("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->handle.last is %s\n",

him->favfood, him->handle.last);

return 0;

}

该程序的输出如下:


address #1: 0x7fff5fbff820 #2: 0x7fff5fbff874

pointer #1: 0x7fff5fbff820 #2: 0x7fff5fbff874

him->income is $68112.00: (*him).income is $68112.00

him->favfood is tripe: him->handle.last is Swillbelly


关键概念


我们在编程中要表示的信息通常不只是一个数字或一些列数字。程序可


能要处理具有多种属性的实体。例如,通过姓名、地址、电话号码和其他信


息表示一名客户;或者,通过电影名、发行人、播放时长、售价等表示一部


电影DVD。C结构可以把这些信息都放在一个单元内。在组织程序时这很重


要,因为这样可以把相关的信息都储存在一处,而不是分散储存在多个变量


中。


设计结构时,开发一个与之配套的函数包通常很有用。例如,写一个以


结构(或结构的地址)为参数的函数打印结构内容,比用一堆printf()语句强


得多。因为只需要一个参数就能打印结构中的所有信息。如果把信息放到零


散的变量中,每个部分都需要一个参数。另外,如果要在结构中增加一个成


员,只需重写函数,不必改写函数调用。这在修改结构时很方便。


联合声明与结构声明类似。但是,联合的成员共享相同的存储空间,而


且在联合中同一时间内只能有一个成员。实质上,可以在联合变量中储存一


个类型不唯一的值。


enum 工具提供一种定义符号常量的方法,typedef 工具提供一种为基本


或派生类型创建新标识符的方法。


指向函数的指针提供一种告诉函数应使用哪一个函数的方法。


本章小结


C 结构提供在相同的数据对象中储存多个不同类型数据项的方法。可以


使用标记来标识一个具体的结构模板,并声明该类型的变量。通过成员点运


算符(.)可以使用结构模版中的标签来访问结构的各个成员。


如果有一个指向结构的指针,可以用该指针和间接成员运算符(->)代


替结构名和点运算符来访问结构的各成员。和数组不同,结构名不是结构的


地址,要在结构名前使用&运算符才能获得结构的地址。


一贯以来,与结构相关的函数都使用指向结构的指针作为参数。现在的


C允许把结构作为参数传递,作为返回值和同类型结构之间赋值。然而,传


递结构的地址通常更有效。


联合使用与结构相同的语法。然而,联合的成员共享一个共同的存储空


间。联合同一时间内只能储存一个单独的数据项,不像结构那样同时储存多


种数据类型。也就是说,结构可以同时储存一个int类型数据、一个double类


型数据和一个char类型数据,而相应的联合只能保存一个int类型数据,或者


一个double类型数据,或者一个char类型数据。


通过枚举可以创建一系列代表整型常量(枚举常量)的符号和定义相关


联的枚举类型。


typedef工具可用于建立C标准类型的别名或缩写。


函数名代表函数的地址,可以把函数的地址作为参数传递给其他函数,


然后这些函数就可以使用被指向的函数。如果把特定函数的地址赋给一个名


为pf的函数指针,可以通过以下两种方式调用该函数:


#include <math.h> /* 提供sin()函数的原型:double sin(double) */


...


double (*pdf)(double);


1121double x;


pdf = sin;


x = (*pdf)(1.2); // 调用sin(1.2)


x = pdf(1.2); // 同样调用 sin(1.2)


第九章目录:

9.1定义和使用结构体变量293


9.1.1自己建立结构体类型293


9.1.2定义结构体类型变量295


9.1.3结构体变量的初始化和引用296


9.2使用结构体数组300


9.2.1定义结构体数组300


9.2.2结构体数组的应用举例301


9.3结构体指针303


9.3.1指向结构体变量的指针303


9.3.2指向结构体数组的指针304


9.3.3用结构体变量和结构体变量的指针作函数参数306


9.6使用枚举类型322


*9.7用typedef声明新类型名326


第九章课后题答案:


C语言程序设计第五版谭浩强课后答案 第九章习题答案_月已满西楼的博客-CSDN博客_在第三题的基础上,编写一个函数input



目录
相关文章
|
1月前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
10天前
|
C语言
【C语言程序设计——入门】基本数据类型与表达式(头歌实践教学平台习题)【合集】
这份文档详细介绍了编程任务的多个关卡,涵盖C语言的基础知识和应用。主要内容包括: 1. **目录**:列出所有关卡,如`print函数操作`、`转义字符使用`、`数的向上取整`等。 2. **各关卡的任务描述**:明确每关的具体编程任务,例如使用`printf`函数输出特定字符串、实现向上取整功能等。 3. **相关知识**:提供完成任务所需的背景知识,如格式化输出、算术运算符、关系运算符等。 4. **编程要求**:给出具体的代码编写提示。 5. **测试说明**:包含预期输入输出,帮助验证程序正确性。 6. 文档通过逐步引导学习者掌握C语言的基本语法和常用函数,适合初学者练习编程技能。
31 1
|
5月前
|
存储 安全 C语言
C语言中的数据类型
C语言中的数据类型
110 1
|
5月前
|
存储 C语言
C语言数据类型、变量和运算符以及printf相关问题
C语言数据类型、变量和运算符以及printf相关问题
|
1月前
|
存储 编译器 C语言
【C语言】数据类型全解析:编程效率提升的秘诀
在C语言中,合理选择和使用数据类型是编程的关键。通过深入理解基本数据类型和派生数据类型,掌握类型限定符和扩展技巧,可以编写出高效、稳定、可维护的代码。无论是在普通应用还是嵌入式系统中,数据类型的合理使用都能显著提升程序的性能和可靠性。
60 8
|
3月前
|
存储 C语言
【c语言】数据类型和变量
本文介绍了C语言中的数据类型和变量。数据类型分为内置类型和自定义类型,内置类型包括字符型、整型、浮点型等,每种类型有不同的内存大小和取值范围。变量分为全局变量和局部变量,它们在内存中的存储位置也有所不同,分别位于静态区和栈区。通过示例代码和图解,详细阐述了这些概念及其应用。
66 1
|
3月前
|
C语言
3.4 C语言基本数据类型2
在C语言中,声明一个整型(int)变量时,需先写入&#39;int&#39;关键字,后跟变量名并以分号结尾。若同时声明多个变量,可在&#39;int&#39;后用逗号分隔列出所有变量名。例如,`int erns;` 或 `int hogs, cows, goats;` 都是合法声明。变量声明后需通过赋值语句如 `cows = 112;` 或使用函数如 `scanf()` 来初始化其值。
75 10
|
3月前
|
存储 程序员 C语言
3.1 C语言基本数据类型
在C语言中,整数类型如`int`类型是很有用的,它属于有符号整型,意味着该类型的值必须是整数,并且可以是正整数、负整数或者零。`int`类型的数值范围依据计算机系统有所不同,通常取决于系统的位宽。例如,在早期16位的IBM PC兼容机上,`int`类型使用16位存储,取值范围为-32768至32767;而在当前32位系统中,使用32位存储,拥有更宽泛的取值范围。随着64位处理器的普及,`int`类型能够存储的整数范围将进一步扩大。根据ISO C标准,`int`类型的最小取值范围被规定为-32768到32767。系统通常会利用一个特殊的位来表示整数的正负。
84 10
|
3月前
|
C语言
3.1C语言基本数据类型
在C语言中,初始化变量是指为变量设定初始值,通常在声明时直接完成,例如 `int cows=32;`。应注意避免在同一语句中混合初始化与未初始化的变量,如 `int dogs, cats=94;` 这样的写法容易引起误解。此外,整型常量如21、32等在C语言中被视为int类型,但非常大的整数则不然,且带有小数点或指数的数值不属于整型常量。
40 9
|
4月前
|
存储 C语言 索引
C 语言数据类型详解
C语言中的数据类型主要包括基本数据类型、构造数据类型和用户定义数据类型。基本类型如整型(`int`)、字符型(`char`)、浮点型(`float`)、双精度浮点型(`double`)和无符号整型(`unsigned int`)。构造类型包括数组(`Array`)、结构体(`Struct`)、共用体(`Union`)和枚举(`Enum`)。用户定义类型则通过`typedef`为已有类型定义新名称,并可通过结构体和共用体自定义复合数据结构。此外,还有指针类型用于存储变量地址,以及`signed`、`unsigned`、`short`、`long`等类型修饰符。
125 11

热门文章

最新文章