一、多级指针
#include <stdio.h>
int main(void)
{
int i = 4;
int * p = &i;
int ** q = &p;
int *** r = &q;
printf("***r = %d", ***r);
return 0;
}
二、动态分配内存实现跨函数使用内存
/*
动态分配内存malloc使得跨函数使用内存
*/
#include <stdio.h>
#include <stdlib.h>
void f(int ** q)
{
*q = (int *) malloc(sizeof(int));
**q = 5; // 等价于*p = 5
// 由于没有free(q),所以函数终止后可以被其他函数使用
}
int main(void)
{
int * p;
f(&p); // 要想通过f函数内部修改p的值,只能发送p的地址,&p是 int **类型
printf("*p = %d\n", *p);
return 0;
}
- 有什么用? 通过函数来建立某内存并返回该首个地址
phead = creat_list()
三、结构体
3.1 创建结构体及初始化方式
#include <stdio.h>
struct Student // 定义一个新数据类型;struct可以放main函数里
{
char name[20];
int age;
}; // 切记“;”不能丢
int main(void)
{
struct Student st1 = {"abnc", 12}, st2; // st={}第一种初始化方式
st2.age = 12; // st.name第二种初始化方式
strcpy(st2.name, "Her"); // 切记,字符串不能用“=”复制,用strcpy
printf("%s %d %d\n", st1.name, st1.age);
printf("%s %d %d\n", st2.name, st2.age);
return 0;
}
3.2 指向结构体变量的指针
#include <stdio.h>
#include <stdlib.h>
struct Student
{
char name[20];
int age;
};
int main(void)
{
struct Student st = {"abnc", 12};
struct Student * pts = &st1; // 创建指向结构体的指针
pts->age = 12; // 第三种初始化方式
strcpy(pts->name, "Bob");
printf("%s %d\n", st.name, st.age);
return 0;
}
- pst->age等价于(*pst).age,也就是等价于st.age;其含义就是
- pst所指向的结构体变量中的age这个成员
3.3 通过函数来完成对结构体变量的输入和输出
#include <stdio.h>
#include <stdlib.h>
struct Student
{
char name[20];
int age;
};
void InputStudent(struct Student * pstu);
void OutputStudent(struct Student * pstu);
int main(void)
{
struct Student st1 = {"abnc", 12};
struct Student * pts = &st1; // 创建指向结构体的指针
InputStudent(pts);
OutputStudent(pts);
return 0;
}
void InputStudent(struct Student * pstu)
{
pstu->age = 100;
strcpy(pstu->name, "Haaaaa");
}
void OutputStudent(const struct Student * pstu) // 这里传入指针更快,因为指针只占1个字节!
// 只读不写的加个const来保护原变量
{
printf("%d, %s\n", pstu->age, pstu->name);
}
3.4 动态构造存放学生管理信息系统(结构体数组)
- 信息系统要求
- 用户输入学生名字和分数
- 输入后对分数进行排序
- 输出排序后的学生信息
- 要求以函数方式写
#include <stdio.h>
#include <stdlib.h>
struct Student
{
char name[100];
int score;
};
void InputStudent(struct Student * pArr, int len);
void OutputStudent(const struct Student * pArr, int len);
void SortStudent(struct Student * pArr, int len);
int main(void)
{
int len;
struct Student * pArr;
printf("请输入学生的个数:\n");
scanf("%d", &len);
pArr = (struct Student *)malloc(len * sizeof(struct Student));
InputStudent(pArr, len); // 传指针,类似于传数组
SortStudent(pArr, len);
OutputStudent(pArr, len);
return 0;
}
void InputStudent(struct Student * pArr, int len) // 接收指针,类似于接数组
{
int i;
for(i = 0; i < len; ++i)
{
printf("请输入第%d个学生的信息:\n", i+1);
printf("name = ");
scanf("%s", pArr[i].name); //name是数组名,本身就已经是数组首元素的地址, 所以pArr[i].name 不能改成 &pArr[i].name
printf("score = ");
scanf("%d", &pArr[i].score); // 指针变量名当数组用
}
}
void SortStudent(struct Student * pArr, int len)
{
int i, j;
struct Student t;
for(i=0; i<len-1; ++i)
{
for(j=0; j<len-1-i; ++j)
{
if(pArr[j].score < pArr[j+1].score)
{
t = pArr[j];
pArr[j] = pArr[j+1];
pArr[j+1] = t;
}
}
}
}
void OutputStudent(const struct Student * pArr, int len)
{
int i;
printf("\n分数排名如下");
for(i = 0; i < len; ++i)
{
printf("\n第%d个学生的信息:\n", i+1);
printf("name = %s", pArr[i].name);
printf("score = %d", pArr[i].score);
}
printf("\n");
}
- 总结:
- 用指针做数组名,也就是说,malloc后,对指针取下标完全可取;传数组指针就是传数组的含义
- 注意指针就是地址,指针变量存的就是地址
- 对于冒泡排序,小于号就是升序;大于号就是降序
- 对于为什么scanf中数组不用“&”:
#include <stdio.h> int main(void) { int a[10]; scanf("%d", a); printf("%d\n", *a); // a等价于第一个元素的地址 return 0; }
- &pArr[i].score,点运算符优先于取地址符