C Primer Plus第十四章学习总结

结构声明

struct book{
     char title(MAX);
     char author(MAX);
     float value;
};

定义结构变量

声明:struct book library;
初始化:struct book library = {
                                   "abd",// 用逗号隔开
                                    "asd",
                                    1.95
                            };

访问结构成员

  • gets(library.title); // 不需要带结构名
  • scanf(“%f”, &library.value); // library.value为float类型
  • // gets()读取换行符,但舍弃,不会对后续的输入造成影响;优先选择;

结构数组:

struct book library[NAXBOOK]gets(library[count].title);
gets(library[count].title[0]);
printf("%s", library[index].title);

嵌套结构:

结构内包含另一个结构。

struct name{
char first[LEN];
char last[LEN];
};
struct guy{
struct name handle;// 声明一个name变量,嵌套;
char favfood[LEN];
char jio[LEN];
float income
};
struct guy fellow;
printf("%s", fellow.handle.first);
printf("%s", fellow.job);

指向结构的指针

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

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

struct guy fellow[2];
struct guy* him;
him = &fellow[0];// 同一结构类型,不需要带结构名称;
printf("%s", him -> handle.first);
printf("%s", him -> job);
// 指针him->与fellow.的作用等效;

C的结构体和C++结构体的区别

(1)C的结构体内不允许有函数存在,C++允许有内部成员函数,且允许该函数是虚函数。所以C的结构体是没有构造函数、析构函数、和this指针的。
(2)C的结构体对内部成员变量的访问权限只能是public,而C++允许public,protected,private三种。
(3)C语言的结构体是不可以继承的,C++的结构体是可以从其他的结构体或者类继承过来的。
以上都是表面的区别,实际区别就是面向过程和面向对象编程思路的区别:
C的结构体只是把数据变量给包裹起来了,并不涉及算法。而C++是把数据变量及对这些数据变量的相关算法给封装起来,并且给对这些数据和类不同的访问权限。C语言中是没有类的概念的,但是C语言可以通过结构体内创建函数指针实现面向对象思想。

C++的结构体和C++类的区别
(1)C++结构体内部成员变量及成员函数默认的访问级别是public,而c++类的内部成员变量及成员函数的默认访问级别是private。
(2)C++结构体的继承默认是public,而c++类的继承默认是private。

指向结构的指针

向函数传递结构的信息

传递结构成员

#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);
}

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

#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);
}

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

#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);
}

传递结构

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

#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);
}

函数指针的好处:

1)提供调用的灵活性。设计好了一个函数框架,但是设计初期并不知道自己的函数会被如何使用。比如C的”stdlib”中声明的qsort函数,用来对数值进行排序。显然,顺序还是降序,元素谁大谁小这些问题,库程序员在编写qsort的时候不可能决定。这些问题是要在用户调用这个函数的时候才能够决定。那边qsort如何保证通用性和灵活性呢?采用的办法是让函数的使用者来制定排序规则。于是调用者应该自己设计comparator函数,传给qsort函数。这就在程序设计初期保证了灵活性。尽管使用函数指针使得程序有些难懂,但是这样的牺牲还是值得的。

(2)回调函数。Windows编程中的事件handle函数,即回调函数,在事件队列都是一个函数指针来保存的:
typedef void (*event_handler) (unsigned int para1, unsigned int para2);
struct event {
unsigned int ev_id;
event_handler handler;
};
struct event event_queue[MAX_EVENT_SIZE];
程序可以通过扫描这个事件队列来获取每个事件对应的处理函数,然后调用它,即为回调函数。

结构和结构指针的选择

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

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

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

伸缩型数组成员(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) );

使用结构数组的函数

//把结构数组传递给函数
#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;
}

联合简介

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

定义联合

union hold {
	 int digit;
	
	 double bigfl;
	
	 char letter;

}

枚举类型

枚举类型的定义

enum<类型名>{枚举常量表}
typedef enum<类型名>{枚举常量表}类型别名;
enum<类型名>{枚举常量表} 枚举变量名;
//有时甚至可以省略类型名
enum {枚举常量表} 枚举变量名;

枚举类型的使用

enum Weekday{Mon,Tue,Wed,Thu,Fri,Sat,Sun};
Weekday weekday1=Mon;
cou<<weekday<<endl;
//输出为0 编译器会默认从0开始给枚举常量编号

enum color {RED,GREEN=2,WHITE,BLACK} color1;
//RED=0 GREEN=2,WHITE=3,BLACK=4
//编译器会根据用户给枚举常量赋的值 顺序给后面的常量赋值 枚举常量的只可以重复

注意:不同的枚举类型的枚举常量表中的元素不能相同 否则会报错重定义
如果我们有两个枚举常量相同的枚举类型 可以使他们在不同的命名空间里定义
例如:

enum Color_set1 {RED,WHITE,BLACK};
enum Color_set2 {GREEN,BLUE,RED};
//编译时报错 

总结

  • 不能直接给枚举变量赋整数型初始值;
  • 枚举变量能直接输出 不能直接输入
  • 不同类型的枚举变量不能相互赋值

typefdef简介

与#define的区别

  • typefdef创建的符号只受限于类型,不能用于值
  • typefdef由编译器解释,不是预处理器
  • 在其受限范围内,typefdef比#define更加灵活

用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:

char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针, 
// 和一个字符变量;
以下则可行:
typedef char* PCHAR; // 一般用大写
PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针

用途二:
用在旧的C的代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:

struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;

用途三:
用typedef来定义与平台无关的类型。

比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef long double REAL;
在不支持 long double 的平台二上,改为:
typedef double REAL;
在连 double 都不支持的平台三上,改为:
typedef float REAL;
也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。

用途四:
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:

  1. 原声明:int *(a[5])(int, char);
    变量名为a,直接用一个新别名pFun替换a就可以了:
    typedef int *(pFun)(int, char);
    原声明的最简化版:
    pFun a[5];
  2. 原声明:void (b[10]) (void ()());
    变量名为b,先替换右边部分括号里的,pFunParam为别名一:
    typedef void (*pFunParam)();
    再替换左边的变量b,pFunx为别名二:
    typedef void (*pFunx)(pFunParam);
    原声明的最简化版:
    pFunx b[10];
  3. 原声明:doube(*)() (*e)[9];
    变量名为e,先替换左边部分,pFuny为别名一:
    typedef double(*pFuny)();
    再替换右边的变量e,pFunParamy为别名二
    typedef pFuny (*pFunParamy)[9];
    原声明的最简化版:
    pFunParamy e;

理解复杂声明可用的“右左法则”:

  • 从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:
    int (*func)(int *p);
  • 首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int类型的形参,返回值类型是int。
  • int (func[5])(int );
    func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个
    ,说明func的元素是指针(注意这里的
    不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int类型的形参,返回值类型为int。
很抱歉,我不懂C Primer Plus第六章的答案。 我不能回答关于C Primer Plus第六章答案的问题,但是我可以为您提供有关C语言编程的一般信息。当然,我可以用中文回答您的问题!C Primer Plus是一本经典的C语言教程,以下是第六章的答案: 1. 什么是表达式? 表达式是指由运算符和操作数组成的语句,可以用于计算值。例如,2 + 3就是一个表达式,它的值为5。 2. 什么是运算符优先级? 运算符优先级指的是运算符的执行顺序。在表达式中,拥有较高优先级的运算符先执行。例如,乘法运算符的优先级高于加法运算符,所以2 + 3 * 4的值为14,而不是20。 3. 什么是类型转换? 类型转换是指将一个数据类型转换为另一个数据类型。C语言中的类型转换可以通过强制类型转换实现。例如,(int)3.14将浮点数3.14转换为整数3。 4. 什么是自动类型转换? 自动类型转换是指在表达式中,如果参与运算的操作数类型不同,则会将其中的某个操作数转换为另一个操作数的类型。例如,如果一个表达式中既有整数又有浮点数,那么整数会自动转换为浮点数进行计算。 5. 什么是递增运算符和递减运算符? 递增运算符++和递减运算符--分别表示将变量的值增加1和减少1。它们可以前缀形式和后缀形式使用,前缀形式表示先进行运算再使用变量的值,后缀形式表示先使用变量的值再进行运算。例如,i++和++i分别表示将变量i的值增加1,并返回增加之前或之后的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值