结构体
数组是用于保存一组相同类型数据的, 而结构体是用于保存一组不同类型数组的
在使用结构体之前必须先定义结构体类型, 因为C语言不知道你的结构体中需要存储哪些类型数据, 我们必须通过定义结构体类型来告诉C语言, 我们的结构体中需要存储哪些类型的数据
struct 结构体名{
类型名1 成员名1;
类型名2 成员名2;
……
类型名n 成员名n;
};
结构体变量占用存储空间大小
结构体的总大小为结构体最宽基本类型元素大小的整数倍
struct Person{
int age; // 4 第一次开辟8byte 剩4
char ch; // 1 不开辟使用第一次开辟剩余的4byte,剩3
double score; // 8 3byte不够分配,第二次开辟8byte
};
struct Person p;
printf("sizeof = %i\n", sizeof(p)); // 16
占用内存最大属性是score, 占8个字节, 所以第一次会分配8个字节
将第一次分配的8个字节分配给age4个,分配给ch1个, 还剩下3个字节
当需要分配给score时, 发现只剩下3个字节, 所以会再次开辟8个字节存储空间
一共开辟了两次8个字节空间, 所以最终p占用16个字节
struct Person{
int age; // 4 第一次开辟88byte 剩4
double score; // 8 不够,第二次开辟8byte
char ch; // 1 无剩,第三次开辟8 byte
};
struct Person p;
printf("sizeof = %i\n", sizeof(p)); // 24
占用内存最大属性是score, 占8个字节, 所以第一次会分配8个字节
将第一次分配的8个字节分配给age4个,还剩下4个字节
当需要分配给score时, 发现只剩下4个字节, 所以会再次开辟8个字节存储空间
将新分配的8个字节分配给score, 还剩下0个字节
当需要分配给ch时, 发现上一次分配的已经没有了, 所以会再次开辟8个字节存储空间
一共开辟了3次8个字节空间, 所以最终p占用24个字节
结构体变量的定义
定义结构体变量:struct 结构体名 结构体变量名;
先定义结构体类型,再定义变量:
struct Student {
char *name;
int age;
};
struct Student stu;
定义结构体类型的同时定义变量
struct Student {
char *name;
int age;
} stu;
匿名结构体定义结构体变量
struct {
char *name;
int age;
} stu;
第三种方法与第二种方法的区别在于,第三种方法中省去了结构体类型名称,而直接给出结构变量,
这种结构体最大的问题是结构体类型不能复用。
结构体变量的初始化
定义的同时按顺序初始化
struct Student {
char *name;
int age;
};
struct Student stu = {“cxx", 22};
定义的同时不按顺序初始化
struct Student{
char *name;
int age;
};
struct Student stu = {.age = 22, .name = "cxx" };
先定义后逐个初始化
struct Student{
char *name;
int age;
};
struct Student stu;
stu.age = 22;
stu.name = "cxx" ;
先定义后一次性初始化
struct Student {
char *name;
int age;
};
struct Student stu;
stu2 = (struct Student){"cxx", 22};
结构体指针
一个指针变量当用来指向一个结构体变量时,称之为结构体指针变量
格式:== struct 结构名 *结构指针变量名==
int main(void)
{
// 定义一个结构体类型
struct Student {
char *name;
int age;
};
// 定义一个结构体变量
struct Student stu = {“lnj", 18};
// 定义一个指向结构体的指针变量
struct Student *p;
// 指向结构体变量stu
p = &stu;
//这时候可以用3种方式访问结构体的成员
// 方式1:结构体变量名.成员名
printf("name=%s, age = %d \n", stu.name, stu.age);
// 方式2:(*指针变量名).成员名
printf("name=%s, age = %d \n", (*p).name, (*p).age);
// 方式3:指针变量名->成员名
printf("name=%s, age = %d \n", p->name, p->age);
return 0;
}
结构体指针成员访问
通过结构体指针访问结构体成员, 可以通过以下两种方式:
(*结构指针变量).成员名
== 结构指针变量->成员名==
字符串定义、初始化:
char string[]="cxx";
printf("%s\n",string); //输出结果:cxx
//数组名保存的是数组第0个元素的地址, 指针也可以保存第0个元素的地址
char *str = "abc"
for(int i = 0; i < strlen(str);i++){
printf("%c-", *(str+i)); //输出结果:a-b-c
}
char name[9] = "cxx"; //在内存中以“\0”结束, \0ASCII码值是0
char name1[9] = {'c,'x','x','\0'};
char name2[9] = {'c','x','x',0};
// 当数组元素个数大于存储字符内容时, 未被初始化的部分默认值是0, 所以下面也可以看做是一个字符串
char name3[9] = {'c','x','x'};
字符串输出:
如果字符数组中存储的是一个字符串, 那么字符数组的输入输出将变得简单方便。
不必使用循环语句逐个地输入输出每个字符
可以使用printf函数和scanf函数一次性输出输入一个字符数组中的字符串
使用的格式字符串为“%s”,表示输入、输出的是一个字符串
输出%s的本质就是根据传入的name的地址逐个去取数组中的元素然后输出,直到遇到 ‘\0’ 位置结束
char name[]="chenc\0hen";
printf("%s\n",name); //输出结果:chenc
//对一个字符串数组, 如果不做初始化赋值, 必须指定数组长度
char name[10];
scanf("%s",name); //输入一串字符
//name最多存放由9个字符构成的字符串,其中最后一个字符的位置要留给字符串的结尾标示‘\0’
//当用scanf函数输入字符串时,字符串中不能含有空格,否则将以空格作为串的结束符;
字符串长度计算:
sizeof关键字:
因为字符串在内存中是逐个字符存储的,一个字符占用一个字节,所以字符串的结束符长度也是占用的内存单元的字节数。
char name[] = "it666";
int size = sizeof(name);// 包含\0结束符
printf("size = %d\n", size); //输出结果:6
strlen函数:
测字符串的实际长度(不含字符串结束标志‘\0’)并作为函数返回值。
char name[] = "it666";
size_t len = strlen(name2);
printf("len = %lu\n", len); //输出结果:5
以“\0”为字符串结束条件进行统计
/**
* 自定义方法计算字符串的长度
* @param name 需要计算的字符串
* @return 不包含\0的长度
*/
int myStrlen2(char str[])
{
// 1.定义变量保存字符串的长度
int length = 0;
while (str[length] != '\0')
{
length++;//1 2 3 4
}
return length;
}
/**
* 自定义方法计算字符串的长度
* @param name 需要计算的字符串
* @param count 字符串的总长度
* @return 不包含\0的长度
*/
int myStrlen(char str[], int count)
{
// 1.定义变量保存字符串的长度
int length = 0;
// 2.通过遍历取出字符串中的所有字符逐个比较
for (int i = 0; i < count; i++) {
// 3.判断是否是字符串结尾
if (str[i] == '\0') {
return length;
}
length++;
}
return length;
}
字符串连接函数:strcat
格式: strcat(字符数组名1,字符数组名2)
功能:把字符数组2中的字符串连接到字符数组1 中字符串的后面,并删去字符串1后的串标志 “\0”。本函数返回值是字符数组1的首地址。
char oldStr[100] = "welcome to";
char newStr[20] = " cxx";
strcat(oldStr, newStr);
puts(oldStr); //输出: welcome to lnj"
本程序把初始化赋值的字符数组与动态赋值的字符串连接起来。
要注意的是,字符数组1应定义足 够的长度,否则不能全部装入被连接的字符串。
字符串拷贝函数:strcpy
格式: strcpy(字符数组名1,字符数组名2)
功能:把字符数组2中的字符串拷贝到字符数组1中。串结束标志“\0”也一同拷贝。字符数名2, 也可以是一个字符串常量。这时相当于把一个字符串赋予一个字符数组。
char oldStr[100] = "welcome to";
char newStr[50] = " cxx";
strcpy(oldStr, newStr);
puts(oldStr); // 输出结果: lnj // 原有数据会被覆盖
本函数要求字符数组1应有足够的长度,否则不能全部装入所拷贝的字符串。
字符串比较函数:strcmp
格式: strcmp(字符数组名1,字符数组名2)
功能:按照ASCII码顺序比较两个数组中的字符串,并由函数返回值返回比较结果。
字符串1=字符串2,返回值=0;
字符串1>字符串2,返回值>0;
字符串1<字符串2,返回值<0。
char oldStr[100] = "0";
char newStr[50] = "1";
printf("%d", strcmp(oldStr, newStr)); //输出结果:-1
char oldStr[100] = "1";
char newStr[50] = "1";
printf("%d", strcmp(oldStr, newStr)); //输出结果:0
char oldStr[100] = "1";
char newStr[50] = "0";
printf("%d", strcmp(oldStr, newStr)); //输出结果:1