t ypedef struct Person Person;
其中struct Person是一个已经存在的结构体类型,后面的Person是我们新起的别名。
给数据类型起别名必须使用typedef
如果希望在多个函数之间共享同一个结构体变量的内容则应该把这个结构体变量的地址作为参数或返回值使用。
指针变量可以和const混合使用,参考练习03const.c
数据对齐指变量的地址必须能被变量的大小整除。如果变量大小超过4则按4计算。
补齐指结构体整体的大小必须是内部最大变量大小的整数倍。如果内部最大变量的大小超过4按4计算。
使用位域可以在声明结构体的时候指定某个具体变量所占的二进制数位。参考练习05bit.c。
联合中所有子变量都是从同一个地址开始分配的,它们互相之间会影响
计算机中存储变量有两种方式,低数位放置在大地址字节中叫大端,低数位放置在小地址的字节里叫小端。
网络上的所有数据都是以大端的方式存储的,这叫做网络字节序列。
枚举类型可以把一组相关的概念统一转换成数字。第一个概念被转换成0,以后的所有概念依次递增。可以在定义枚举类型的时候指定某个概念应该转换成数字几,这会影响到后面的所有概念的转换。
malloc函数用于从堆中分配内存空间,需要通过参数告诉他需要分配的内存空间是多少个字节。这个函数返回一个地址数据表示分配好的内存空间中第一个字节的地址。需要对这个地址数据进行类型转换成具体的指针类型再使用。
堆中变量的生命周期由程序来控制,一旦堆中的变量不再需要使用就必须使用free函数释放他们。这个函数需要一个地址数据作为参数,这个地址数据应该是对中某段分配好的内存空间的首地址。
malloc函数分配的内存空间里面的数据是不确定的。
calloc函数也可以从堆中分配内存空间,这个函数会把分配的所有变量都清0
realloc函数可以调整一段已分配好的内存空间的大小,参考08heap.c练习
realloc(NULL, 12) 相当于直接分配12个字节的空间,类似malloc(12)
realloc(p, 0)相当于释放一段已经分配好的内存空间,类似free(p)
二级指针用来记录普通指针变量的地址,声明语法如下
char **pp_str = NULL;
其中**表示二级指针
二级指针的主要用途是作为参数使用,它可以在多个函数之间共享同一个一级指针变量
函数名称代表了函数的地址,函数指针变量可以用来记录函数的地址数据。函数指针的声明语法是从函数声明语法变换的来的。函数指针可以直接当函数名使用。
qsort函数可以用来对一个数组中的所有变量进行排序,它需要我们提供一个函数的地址用来比较数组中两个变量的大小。
/*
结构体练习
*/
#include <stdio.h>
/*struct Person {
char gender;
int age;
float height;
};
typedef struct Person Person;*/
typedef struct /*Person*/ {
char gender;
int age;
float height;
} Person;
//#define Person struct Person 不可以使用#define给数据类型起别名
void read(Person * p_Person) {
printf("请输入性别,年龄和身高:");
scanf("%c %d %f", &(p_Person->gender), &(p_Person->age), &(p_Person->height));
}
void show(const Person* p_Person) {
//p_Person->age = 0; //因为参数是const指针所以这条语句编译会报错
printf("性别是%c,年龄是%d,身高是%g\n", p_Person->gender, p_Person->age, p_Person->height);
}
int main() {
//struct Person person;
Person person;
//struct Person person = {'F', 23, 1.78};
read(&person);
show(&person);
return 0;
}
/*
typedef练习
*/
#include <stdio.h>
//#define PINT int * //会造成声明多个变量的时候只有第一个变量是指针类型
typedef int* PINT;
int main() {
PINT p_value = NULL, p_value_1 = NULL;
return 0;
}
/*
const指针变量练习
*/
#include <stdio.h>
int main() {
int value = 0;
const int * p_value = &value;
int * const p_c_value = &value;
//*p_value = 5; //不可以通过const指针修改变量数值
p_value = NULL; //编译可以成功
*p_c_value = 5; //编译可以成功
//p_c_value = NULL; //不可以对这种指针变量赋值
return 0;
}
/*
对齐和补齐练习
*/
#include <stdio.h>
/*typedef struct {
char ch1;
char ch2;
int value;
} A;*/
typedef struct {
char ch1;
int value;
char ch2;
} A;
int main() {
A a;
printf("sizeof(A)是%d\n",sizeof(A));
printf("%p %p %p\n", &a.ch1, &a.ch2, &a.value);
return 0;
}
/*
结构体位域练习
*/
#include <stdio.h>
typedef struct {
char mine:1;
char num:4;
char status:2;
} pos;
/*typedef struct {
int mine:1;
int num:4;
int status:2;
} pos;*/
int main() {
pos p;
printf("sizeof(pos)是%d\n", sizeof(pos));
//printf("%p\n", &p.num); //不可以访问用位域声明的子变量的地址
return 0;
}
/*
联合练习
*/
#include <stdio.h>
typedef struct {
char ch[2];
int value;
} A;
typedef union { //联合声明语法
char ch[2];
int value;
} B;
int main() {
B b;
printf("sizeof(B)是%d\n", sizeof(B));
printf("%p %p\n", b.ch, &b.value);
b.ch[0] = 0; //联合内部的各子变量会互相影响
b.value = 5;
printf("%d\n", b.ch[0]);
b.value = 0x12345678;
if (0x78 == b.ch[0]) {
printf("小端\n");
}
else {
printf("大端\n");
}
return 0;
}
/*
枚举练习
*/
#include <stdio.h>
int main() {
enum Season {SPR, SUM = 5, AUT, WIN};
printf("AUT是%d\n", AUT);
if (WIN == 7) {
printf("WIN是7\n");
}
return 0;
}
/*
堆操作练习
*/
#include <stdio.h>
#include <stdlib.h>
int main() {
int loop = 0, num = 0;
printf("请输入数字的个数:");
scanf("%d", &num);
//int * p_value = (int*)malloc(num * sizeof(int)); //分配的内存空间没有初始化
int * p_value = (int*)calloc(num, sizeof(int)) ; //这个函数从堆中分配内存空间后会把每个变量初始化成0
if (!p_value) { //如果分配内存失败则得到NULL,每次从堆中分配内存后都需要检测这个条件
printf("内存分配失败\n");
return 0;
}
for (loop = 0; loop < num; loop++) {
printf("%d ", p_value[loop]);
}
printf("\n");
for (loop = 0; loop < num; loop++) {
printf("请输入一个整数:");
scanf("%d", &p_value[loop]);
}
for (loop = num - 1; loop >= 0; loop--) {
printf("%d ", p_value[loop]);
}
printf("\n");
int *p = realloc(p_value, 12); //如果失败返回NULL
if (p) {
p_value = p;
num = 3;
}
for (loop = 0; loop < num; loop++) {
printf("%d ", p_value[loop]);
}
printf("\n");
free(p_value); //必须要在使用完成后释放从堆中分配的内存空间
p_value = NULL; //避免出现野指针
return 0;
}
/*
字符串分解练习
*/
#include <stdio.h>
#include <stdlib.h>
char * split(char * str, char ** pp_str) {
int loop = 0;
for (loop = 0;':' != *(str + loop) &&
'\0' != *(str + loop);loop++);
*pp_str = (char*)malloc(loop + 1);
if (!*pp_str) {
return NULL;
}
for (loop = 0;':' != *(str + loop) &&
'\0' != *(str + loop);loop++) {
*(*pp_str + loop) = *(str + loop);
}
*(*pp_str + loop) = 0;
if (0 == *(str + loop)) {
return NULL;
}
else {
return str + loop + 1;
}
}
int main() {
char str[100] = {0};
char res[10] = {0};
char * p_str = NULL;
char * p_str_1 = NULL;
printf("请输入一个字符串:");
fgets(str, 100, stdin);
p_str_1 = split(str, &p_str);
if (p_str) {
printf("%s\n", p_str);
free(p_str);
p_str = NULL;
}
if (p_str_1) {
printf("%s\n", p_str_1);
}
return 0;
}
/*
函数指针练习
*/
#include <stdio.h>
int add(int x, int y) {
return x + y;
}
int main() {
int (*p_add)(int, int) = add; //函数指针变量声明
typedef int (*p_func)(int, int); //函数指针类型声明
p_func p_add_1 = add; //用函数指针类型声明函数指针变量
printf("add是%p,p_add是%p\n", add, p_add);
printf("p_add(2,6)是%d\n", p_add(2, 6));
printf("p_add_1(2,5)是%d\n", p_add_1(2, 5));
return 0;
}
/*
qsort练习
*/
#include <stdio.h>
#include <stdlib.h>
int compare(const void* p_value, const void* p_value_1) {
const int* p_1 = (const int*)p_value;
const int* p_2 = (const int*)p_value_1;
if (*p_1 > *p_2) {
return 1;
}
else if (*p_1 < *p_2) {
return -1;
}
else {
return 0;
}
}
int compare1(const void *p_value, const void *p_value_1) {
return 0 - compare(p_value, p_value_1);
}
int main() {
int value[] = {34, 7, 25, 143, 87}, loop = 0;
qsort(value, 5, sizeof(int), compare);
for (loop = 0; loop <= 4; loop++) {
printf("%d ", value[loop]);
}
printf("\n");
qsort(value, 5, sizeof(int), compare1);
for (loop = 0; loop <= 4; loop++) {
printf("%d ", value[loop]);
}
printf("\n");
return 0;
}