一、学习目的
指针是C语言中的一种概念,正确而灵活地运用指针可以使程序简洁,紧凑。 指针能够解决跨区域(不同作用域,不同的代码块)之间的数据交互,为程序编写提供很大的便利;
C语言提供了一些由系统已定义好的数据类型,也允许用户建立自己的由不同数据组成的组合型的数据结构,称为结构体,结构体增加了数据之间的内在联系
二、学习内容
1,指针
将地址形象化地称为“指针”
‘*’:1,表示声明定义变量的时候 表示一个指针变量
int *p;定义一个指针变量,这个指针变量只能存放地址(int类型的地址),不能存放具体的数;它指向的内存空间只能存放整数
注意:定义指针变量一定要给初值 不确定时赋值NULL;
float *c = NULL;NULL指向内存的起始地址
2,除了定义指针变量外 那就是访问某个地址的值
float a = 100.1;
float *c = &a;
printf("%f",*c); 输出100.1;
‘&’:取某个变量的地址
void test(int *temp){ //temp实参
temp++;
}
int test1(int a){
a++;
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a = 10;
int *pa = &a;
test(&a); //a的值发生改变 a实参
test1(a) //a的值不变,形参
int(*pFunc)(int) = test1; //函数指针 函数名就是函数在内存中的首地址
指针变量占八个字节 ,注意:sizeof(数组名)会打印出整个数组所占的内存空间,而不是数组首个元素的所占的内存
printf("%lu\n",sizeof(a)); //输出 4
printf("%lu\n",sizeof(pa)); //输出 8
printf("%lu\n",sizeof(a2)); //40 数组名 打印整个数组在内存中占据的字节
printf("%lu\n",sizeof(pa2)); //8
printf("%lu\n",sizeof(pFunc)); //8 指针变量(不管什么类型)在64位系统占8个字节
指针和数组的关系:数组名并不是一个变量,没有分配内存空间 指针变量有内存空间;区别:定义一个数组 系统会分配内存空间 可以存值
int score[5] = {91,92,93,94,95};
printf("%p\n",score); // 输出0078F968
printf("%p\n",&score);//输出0078F968
for(int i=0;i<5;i++){
printf("%d ",score[i]);
}
for(int i=0;i<5;i++){
printf("%d ",*(score+i));
}
printf("%p\n",score);
printf("%p\n",score+1);
printf("%d\n",*(score+1));
printf("%d\n",*score+1); //score[0]+1
printf("%d\n",(*score)++); //91
printf("%d\n",score[0]); //92 前面已经+1
printf("%d\n",++(*score)); //93 再次+1然后输出
指针变量存值的存值的三种方式:
1,指针变量已指向某块区域
int a3=10;
int *p = &a3;
*p = 30;//赋值正确
2,,指针指向一个数组
int num2[10]={};
int *pNum = num2;
*(pNum+1) = 20;
pNum[1] = 30; //*(pNum+i)相当于pNum[i];
第一,第二种都是变量和数组已经分配了内存空间,指针指向变量和数组,所以能够操作这些空间,因此能够赋值;
3,动态分配内存 用malloc() realloc() 方法
注意:自己分配的内存空间必须自己释放 free(); 普通变量的内存是系统分配的,由系统自己释放
char *pName = malloc(3 * sizeof(char));
//判断分配是否成功
if(pName == NULL){
//分配失败
exit(EXIT_FAILURE);
}
pName[0] = 'x';
pName[1] = 'w';
pName[2] = 'j';
printf("%s\n",pName);
当之前分配的内存不够是时,就需要在之前的基础上重新分配 ;realloc() 必须是之前malloc分配的内存才可以用realloc重新再分配 系统自己分配的内存空间不能用这个方法
pName = realloc(pName,4*sizeof(char));
pName[4] = 'o';
printf("%s\n",pName);
free(pName); //释放内存
2,结构体
结构体:声明一种类型 struct Person 类比int float char类型
struct Person{
char name[10];
int age;
char *addr;
};
//定义一个结构体变量变量
Person per1;
Person per2 = {"zhangsan",19};
per1.name = "lisi"; //出错 数组一旦定义 地址不能改变
//不能直接给数组赋值
//若要赋值
per1.name[0] = 'l';
per1.name[1] = 'i';
per1.name[2] = 's';
per1.name[3] = 'i';
// per1.addr = "西南大学"; //正确 常量字符串的地址是由系统自动分配的
per1.addr[0] = 'S';
per1.addr[1] = 'W';
per1.addr[2] = 'U'; //出错 字符指针赋值 必须要有内存 赋值前必须分配内存空间 per1.addr = malloc(4*sizeof(char));
// typedef 类型重命名
3,链表
链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构,链表中每一个元素称为结点,每个结点都应包括两个部分:1,用户需要用的实际数据;2,下一节点的地址。链表中各元素在内存中的地址可以不是连续的
struct Node{ //单链表
int date; //数据域
Node *Next; //指针域
};
struct Node{ //双链表
int date;
Node *next; //后节点指针
Node *previous//前节点指
};
初始化头结点
//初始化头结点 有返回值
Student *initHeader(){
//动态分配内存
Student *pTemp = malloc(1*sizeof(Student))
//初始化
pTemp->next = NULL;
return pTemp;
}
//无返回值
void *initHeader(Student **pHeader){
//动态分配内存
Student *pTemp = malloc(1*sizeof(Student));
//初始化
pTemp->next = NULL;
//改变外部的值
*pHeader = pTemp;
}
4,文件
打开文件 如果文件不存在 则创建一个新文件
FILE *fp = fopen("C:/Users/asus/Desktop/abc.txt","w+")
文件的操作:
r 只读 文件不存在就报错 从头开始读
w 只写 文件不存在就创建 从头开始写 之前存在的内容会被覆盖
a 只写 文件不存在就创建 从末尾开始写
r+,w+,a+ 可读可写
struct Student{
//内存对齐
char name[10]; //优化为占12个字节 int的倍数,浪费2个 所以12+4=16
int age;
};
Student xw1 = {"xw",20};
//将结构体写到文件
fwrite(&xw1,sizeof(Student),1,fp);
三、学习感悟
对于这次学习的内容,其他的还行,我感觉最难受的就是指针了指针这个概念比较复杂,使用也很灵活,因此刚使用常会出错,所以在使用时要十分小心,多思考,多比较,多敲代码,在实践中掌握它。