目的
学习并使用指针和结构体
1.为什么要用指针?
2.怎么使用指针?
技术
1.指针
指针问题从两方面考虑:地址 内存空间
我们之所以使用指针,是用它来解决跨区域(不同作用域 不同代码块)之间的数据交互
两个符号的意义
'*':
1.声明/对应变量的时候 表示一个指针变量
float b=20;
int c=10;
int *a;定义一个指针变量 指向的内存空间只能存放整数
注意:定义指针变量的时候一定要给初值 不确定就给null
int *a=b;错误 指针变量只能存储地址 不能存储具体值
int *a=&b;错误 整形指针只能存储整形变量的地址
int *a=&c;正确
float *d+null;null指向内存的起始地址 0x00
2.除了定义指针变量外 都是访问某个地址的值
int *temp=&c//定义指针变量
*temp=21;//访问temp地址里面的数据 赋值为21
‘&’: 取某个变量的地址
另外
%p:打印 int * 型 即打印地址
"%d",*a:打印指针a地址内的内容
2.数组和指针的关系
数组名并不是一个变量 没有分配内存空间 int a=10;
指针变量是有内存空间的
指针变量本身占据8个字节的内存空间
ps:赋值数组某个的值 的2种方法
int num[20]={};
int *pNum=num;
pNum[0]=29;—等价于—*(pNum+0)=29;
区别:
//定义一个数组 系统会分配内存空间 可以存值
int num[10] = {};
//定义一个指针变量 只为变量本身分配8个字节内存空间
//无法存值,因为没有为他分配可以存值的内存空间
给指针指向的区域赋值
//1.指针变量已经指向某块区域
int a3 = 10;
int *pA = &a3; //指向变量a的内存地址
*pA = 30;
//2.指针指向一个数组
int num2[10] = {};
int *pNum = num2; //指向数组num2的首地址
*(pNum+0) = 20;
pNum[0] = 20;
*(pNum + 1) = 30;
pNum[1] = 30;
//3.动态分配内存 malloc realloc free
//分配一个属于自己的内存空间
//自己分配的内存空间必须自己释放
//普通变量的内存是系统自己分配 所以系统自己负责释放
char *pName = malloc(3 * sizeof(char));
//判断分配是否成功
if(pName == NULL){
//分配失败
exit(EXIT_FAILURE);
}
pName[0] = 'j';
pName[1] = 'a';
pName[2] = 'c';
//当之前分配的内存空间不够了 就需要在之前的基础上重新分配
//realloc 必须是之前使用malloc分配过的
//如果是系统分配的内存 是不能使用realloc的用完了就要自己释放内存
pName = realloc(pName, 4*sizeof(char));
pName[3] = 'k';
printf("%s\n", pName);
free(pName);
3.结构体
结构体是一种数据类型 复合数据类型
一般形式:
struct Person {
char name[10];
char *addr;
int age;
};
结构体中用指针和数组的区别
struct Person xw;
//xw.name = "小王";//数组一旦定义 地址不能改变
//不能直接给数组赋值
xw.name[0] = 'x';//系统为这个变量分配内存了
xw.name[1] = 'w';
//xw.addr = "澳大利亚";//常量字符串的地址是由系统分配的
//先为addr分配内存
xw.addr = malloc(4 * sizeof(char));
xw.addr[0] = 'S';//字符指针赋值 必须要有内存
xw.addr[1] = 'o';
xw.addr[2] = 'u';
xw.addr[3] = 't';
xw.age = 30;
printf("name:%s\n", xw.name);
printf("addr:%s\n", xw.addr);
4.数据持久化
先找到桌面的文件路径 如:C:\Users\header\Desktop
再将文件名加上 后如:C:\Users/HP\Desktop\abc.txt
注意:文件路径找到后使用的时候要把''改为'/' 如:C:/Users/HP/Desktop/abc.txt
//mode 文件的操作模式
// r 只读 文件不存在就报错 从头开始读
//w 只写 文件不存在就创建 从头开始写
//a 只写 从末尾开始写
//r+ w+ a+ 可读可写
FILE *fp = fopen("C:/Users/HP/Desktop/abc.txt", "r");
//写入数据
//音频 视频 图片 -> 二进制数据
//fputs("abc", fp);
struct Student{
char name[10];
int age;
};
//struct Student zx1 = {"zhangxiao", 20};
//将结构体写到文件里面去
//fwrite(&zx1, sizeof(struct Student), 1, fp);
//读取数据
//char temp[20] = {};
//fgets(temp, 5, fp);
//printf("%s\n",temp);
struct Student xw1;
fread(&zx1, sizeof(struct Student), 1, fp);
printf("name: %s\n",zx1.name );
printf("age: %d\n", zx1.age);
//关闭文件
fclose(fp);
return 0;
}
实际应用:模拟学生查成绩系统
image.png
(其中用文件来实现数据持久化)
#import
/*
1. 读取文件内容
内容是什么: 学生信息 -> 结构体
怎么存储:数组 不是最优解
链表 是最优解
线性表 栈 单链表 双链表 二叉树树 图 哈希表
2. 显示界面
Update Delete Insert Select
3. 保存数据
*/
//定义一个学生的结构体节点
typedef struct Node{
char name[10];
int _id;
float score;
struct Node *next;
} Student;
//初始化一个头结点
void initHeader(Student **pHeader){
//动态分配内存
Student *pTemp = malloc(1 * sizeof(Student));
//初始化
pTemp->next = NULL;
//改变外部的值
*pHeader = pTemp;
}
void showMenu(void){
printf("************\n");
printf("1.信息查询\n");
printf("2.信息删除\n");
printf("3.信息更改\n");
printf("4.信息录入\n");
printf("5.退出\n");
printf("************\n");
}
int getChoice(void){
int c;
printf("请您选择操作:");
scanf("%d", &c);
return c;
}
void MyExit(int status){
printf("**************\n");
printf("感谢你的使用再见\n");
printf("**************\n");
}
//保存数据
void save(Student *pTemp){
}
void insert(Student *pTemp){
//准备一个结构体 保存数据
Student *pStu = malloc(1 * sizeof(Student));
pStu->next = NULL;
//提示用户输入
printf("请输入姓名:");
scanf("%s", pStu->name);
printf("请输入成绩:");
scanf("%f", &(pStu->score));
//插入
int count = 0;
while (pTemp -> next != NULL) {
pTemp = pTemp->next;
count++;
}
//自动编号
pStu->_id = count+1;
//将当前这个学生添加到最后一个节点就可以了
pTemp->next = pStu;
}
void querry(Student *pTemp){
//指向第一个数据节点
pTemp = pTemp -> next;
while (pTemp != NULL ) {
printf("id:%d\n", pTemp->_id);
printf("name:%s\n", pTemp->name);
printf("score:%.1f\n",pTemp->score);
printf("\n");
pTemp = pTemp->next;
}
}
int main(int argc, const char * argv[]) {
//定义一个指针 记录头结点
Student *pHeader = NULL;
//初始化头结点
initHeader(&pHeader);
int choice = 0;
while(1){
showMenu();
choice = getChoice();
switch (choice) {
case 1:
//查询
querry(pHeader);
break;
case 2:
break;
case 3:
break;
case 4:
//录入
insert(pHeader);
printf("录入成功!!!\n");
break;
default:
MyExit(EXIT_SUCCESS);
break;
}
}
return 0;
}
感悟
今天的内容有点多,也很难,不过这篇的目的还是在指针和结构体,以后面试的话C语言面到的题重点会有指针,而指针和结构体容易一起出现,所以要好好理解学习,至于那个文件实现数据持久化属于附加内容,链表也是,这些内容单独来看并不是很难理解,但结合在一起使用还是让人掉头发,终于理解脱发的苦恼QAQ。
最后,如果你已经打算要仔细学习这里面的内容,记得买一瓶育发液哦。
图片发自简书App