06.复合数据类型
字符
字符类型、字符文字与量
定义格式:char ch; const char cch = 'C';
字符文字使用单引号对
实际存储时字符类型量存储字符的对应ASCII值
可使用signed与unsigned修饰字符类型
单字符用8个字节存储,表达范围-128127,用unsigned修饰的话范围为0255
字符表示的等价性
char a = 'A';
char a = 65; //ASCII值
char a = 0101; //八进制
char a = 0x41; //十六进制
ASCII码表
控制字符、通信专用字符、可打印字符
回车与换行
Windows: \n\r
Linux:\n
Mac: \r
ASCII使用示例:
判断某个字符是否为数字
bool isDigit(char c)
{
if(c >= '0' && c <= '9') //等价于if(c >= 48 && c <= 57)
return true;
else
return false;
}
将字符转换为大写字符
char ToUpperCase(char c)
{
if(c >= 'a' && c <= 'z')
return c - 'a' + 'A'; //等价于return c + 32;
else
return c;
}
C标准字符特征库:ctype.h/cctype
,标准字符特征库常用函数:bool isalnum(char c);bool isalpha(char c);bool isdigit(char c);bool islower(char c);bool isspace(char c);bool isupper(char c);char tolower(char c);char toupper(char c);
数组
数组的意义与性质
数组的定义
定义格式:元素类型 数组名称[常数表达式];
示例:int a[8]; //定义包含8个整数元素的数组
特别说明
常数表达式必须是常数和常量,不允许为变量
错误示例:int count = 8; int c[count];
数组元素编号从0开始计数,元素访问格式为a[0],a[1],a[2]...
不允许对数组进行整体赋值操作,只能使用循环逐一赋值元素
错误示例:int a[8], b[8]; a = b;
意义与性质
将相同性质的数据元素组织成整体,构成单一维度上的数据序列
数组的存储表示
数组元素一次连续存放,中间没有空闲空间
数组的地址
数组的基地址:数组开始存储的物理位置
数组首元素的基地址:数组首个元素开始存储的物理地址,数值上总是与数组基地址相同
“&”操作符:&a获得数组的基地址;&a[0]获得数组首元素的基地址
设数组基地址为p,并设每个元素的存储空间为m,则第i个元素的基地址为p+mi
数组元素的初始化
基本初始化格式
定义格式:元素类型 数组名称[元素个数] = {值1, 值2, 值3, ……};
示例:int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
初始化时忽略元素个数表达式
在全部元素均初始化时可以不写元素个数,使用sizeof操作符可以获得元素个数
示例:int a[] = {1, 2, 3, 4, 5, 6, 7, 8}; int num_of_elements = sizeof (a) / sizeof (a[0]);
sizeof获取数组存储空间大小(以字节为单位),sizeof(a[0])获取数组首元素的存储空间大小。
数组元素的访问
数组与函数
数组元素作为函数实际参数
int Add(int x, int y) {return (x + y);}
int a[2] = {1, 2}, sum;
sum = Add(a[0], a[1]);
数组整体作为函数形式参数
数组整体作为函数形式参数
基本格式:返回值类型 函数名称 (元素类型 数组名称怕[], 元素个数类型 元素个数)
示例:void GenerateIntegers(int a[], unsigned int n);
特别说明:作为函数形式参数时,数组名称后的中括号内不需列写元素个数,必须使用单独的参数传递元素个数信息
数组作为函数参数时有个巨大的优势,是能够将函数内部对数组元素的修改带出函数以外,能对数组产生实际改变。即数组作为函数参数时既是输入的一部分也是输出的一部分。
示例:
随机产生n个介于[lower,upper]之间的整数并保存在数组中
void GenerateIntegers(int a[],unsigned int n, int lower, int upper)
{
unsigned int i;
for(i = 0;i < n;i++)
a[i] = GenerateRandomNumber(lower,upper);
}
上述代码中,对a[]数组的实际操作真正反映到了a[]中。同时需注意,C++中数组声明时数组元素个数必须为常数或常量(C中只能为常数),所以需额外传一个参数n表示数组元素个数,而不能将元素个数写死或直接声明a[n]。
上述问题的完整描述:使用单独数组名称作为函数实际参数,传递数组基地址而不是数组元素值;形式参数与实际参数使用相同存储区,对数组形式参数值的改变会自动反应到实际参数中
多维数组
多维数组的定义
定义格式:元素类型 数组名称[常数表达式1] [常数表达式2] ...;
示例一:int a[2][2]; //2*2的整型二维数组
示例二:int b[2] [3] [4] ; //2*3*4的整型三维数组
多维数组的初始化
与一维数组类似:int a[2][3] = {1, 2, 3, 4, 5, 6};
单独初始化每一维:int a[2][3] = {{1, 2, 3}, { 4, 5, 6} };
多维数组的存储布局
同一维数组,先行后列存储。
结构体
结构体的意义与性质
结构体的意义
与数组的最大差别:不同类型数据对象构成的集合
当然也可以为相同类型的但具体意义或解释不同的数据对象集合
结构体类型的定义:注意类型定义后面的分号
struct 结构体名称
{
成员类型1 成员名称1;
成员类型2 成员名称2;
......
成员类型3 成员名称3;
};
示例
日期结构体
struct DATE
{
int year;
int month;
int day;
};
复数结构体
struct COMPLEX
{
double real;
double imag;
};
结构体类型的声明
仅仅引入结构体类型的名称,而没有给出具体定义,其具体定义在其他头文件中或本文件后续位置
如何表示学生信息?
成员:整数类型的学号id、字符串类型的姓名name、性别(单独定义枚举类型)gender、年龄age、字符串类型的地址addr
enum GENDER{FEMALE,MALE};
struct STUDENT
{
int id;
STRING name; //假设已有字符串类型的定义
GENDER gender;
int age;
STRING addr;
};
结构体的存储表示
按照成员定义顺序存放
各成员的存储空间一般连续
特殊情况
因为不同硬件和编译器的原因,不同类型的成员可能会按照字(两个字节)或双字(四个字节)对齐后存放
使用sizeof获得结构体类型量占用空间大小(以字节为单位),下述两种方式均可:sizeof date;
sizeof(date);
结构体数据对象的访问
结构体类型的变量与常量:按普通量格式定义
示例一:DATE date;
示例二:STUDENT zhang_san;
示例三:STUDENT students[8];
结构体量的初始化
示例四:DATE date = {2008, 8, 8};
结构体量的赋值
与数组不同,结构体量可直接赋值,拷贝过程为逐成员一一复制
示例五:DATE new_date; new_date = date;
结构体成员的访问
使用点号操作符(成员选择操作符)“."解析结构体量的某个特定成员
示例一:DATE date; date.year = 2008; date.month = 8; date.day = 8;
嵌套结构体成员的访问
可以连续使用点号逐层解析
示例二:
struct FRIEND{int id; STRING name; DATE birthday;};
FRIEND friend;
friend.birthday.year = 1988;
复杂结构体成员的访问
FRIEND friends[4];
friends[0].birthday.year = 1988;
结构体与函数
编写一函数,使用结构体类型存储日期,并返回该日在该年的第几天信息,具体天数从1开始计数,例如2016年1月20日返回20,2月1日返回32
unsigned int GetDateCount(DATE date)
{
static unsigned int days_of_months[13]=
{0,31,28,31,30,31,31,31,31,30,31,30,31};
unsigned int i, date_id = 0;
for(i = 1;i < date.month;i++)
date_id += days_of_months[i];
date_id += date.day;
if(date,month > 2 && IsLeap(date.year))
date_id++;
return date_id;
}