C语言基础-指针篇
文章目录
- 指针篇
- 一、什么是指针:
- 二、如何定义指针变量:
- 三、指针的概念总结:
-
- 1.变量的访问有两种方式 :
- 四、通过指针来访问变量
- 五、指针的使用:
-
- 1.指针分类型
- 六、为什么用指针?
-
- 1.若要用函数来封装交换:(需要用指针)
- 七、指针的重点:
- 八、指针数组:
-
- 1.若要遍历来查看指针数组的地址:
- 2.定义指针数组:
- 九、数组指针:
- 十、函数指针
-
- 1. 如何定义一个函数指针?
- 2. 如何给函数指针赋值?
- 3. 如何通过函数指针调用函数?
- 十一、无类型指针(void) 无类型&&malloc
- 十二、关于malloc的面试问题:
-
- 1.内存泄漏:
- 2.malloc如何使用?
- 十三、 指针收官 !!!!!!
指针篇
一、什么是指针:
指针 = 地址
-
取地址(&hello) //&取地址 取变量名所代表的变量的内存地址
-
若要取地址里面的值:*(&hello); // 此时 " * "代表的是一个运算符,跟+ - / * 运算符类似,该运算符的功能是取出内存地址中的数据的值(取内容)。
-
int 整型变量 存放的是整数 char 字符变量 存放的是字符 int array[3]={1,2,3};数组 存放的是一串数据
问:什么变量能存放地址呢? 答:指针变量存放的是地址。
二、如何定义指针变量:
int *p; //指针变量 存放的就是地址
p = &a; //给指针变量赋值。
int *p2 = &a; //定义并且初始化一个指针变量
” * “ 只有在定义一个指针变量的时候,才是指针的一个标识符 ,在其他情况下,都是一个取内容的运算符
三、指针的概念总结:
1.变量的访问有两种方式 :
第一种: 变量名 (如花店名,你可以一路以花店的名字问路找到花店) 第二种: 取地址 (取变量名所代表的变量的内地址) 如 **int a =10 ; &a(0x660cffc0)**
-
此时 " * "代表的是一个运算符,跟+ - / * 运算符类似,该运算符的功能是取出内存地址中的数据的值(取内容)。
int a =10; a是变量名 *(&a) 地址 -
变量
整型变量 存放的是整数 int a; a=10;
字符变量 存放的是字符 char c; c=‘A’;
指针变量存放的是地址 int *p =&a; char *p; p=&c;
只有在定义一个指针变量的时候,才是指针的一个标识符,在其他情况,都是一个取内容的运算符
指针 = 地址
指针变量 1.存放指针的变量 2.存放地址的变量
四、通过指针来访问变量
int *p1; //标签 代表是一个指针变量
p1 = &hello;
printf("hello的地址是:%p\n ",p1 ); //&取地址 ,取变量名所代表的变量的内存地址。
int *p2 = &meiguitai;
printf(“通过mei的地址来获取mei=%d\n” , *p2); //*取内容符,取变量名所代表的变量的内存地址内的值。
五、指针的使用:
1.指针分类型
- 指针与整数:
int *p;int a=10; p = &a; //整型指针只能指向整型数据 ,只能存放整型地址。
printf(" a = %d \n " , *p); //用指针来访问数据值
int *p; char c=‘A’; p=&c; //在判断计算机的大小端
指针分类型,指针++根据类型不同,偏移值也不同
//指针++1 按类型 整型类型往后++是退4个字节 字符是1个字节
- 指针与数组:
数组: int array[3]={1,2,3}; //数组,关心的是数组的首地址
两种表示方式:1.数组名 = 地址 2.第一个元素的地址
若看到乱码 注意指针偏移的位置,不要超出了数组
printf(“第一个元素的地址是%p\n”,&array[0]);
printf(“第二个元素的地址是%p\n”,&array[1]);
printf(“第三个元素的地址是%p\n”,&array[2]);
- 若要遍历来查看数组的地址:
int array[3]={1,2,3}; for(i=0;i<3;i++){ printf("%d",array[i]); }
六、为什么用指针?
- 指哪打哪——指定内存位置,给它赋值
- 经典数据交换——参数传递要用地址
c语言的指针可以做到把a(10)数据 强制保持在我要的地址 0060ff00 (在ARM架构 裸机编程 ARM 驱动)
案例二:强制保持在我要的地址 0060ff00
int *p = (int *)0x0060ff00; //强制保存在我要的地址 0060ff00*p = 10;printf("在内存的%p位置,存放值是%d\n"p,*p);volatile int *p = (volatile int *)0x0060ff00; //强制保持在我要的地址0060ff00
1.若要用函数来封装交换:(需要用指针)
void swap (int *a ,int *b){int tmp;tmp = *a; //这里的*a是取内容*a = *b;*b=tmp;}int main(){int a=10;int b=5;swap(&a,&b); //调用交换函数return 0;}
七、指针的重点:
-
变量访问的两种方式:
a.变量名 b.指针 -
指针
a.指向谁(类型)p=&a
b.偏移后指向谁 p++ -
整型指针只能指向整型数据,只能存放整型地址
八、指针数组:
-
int *parry; parray = &array[0]; //也可以写 parray =array; 因为数组名也是地址
printf(“第一个元素的地址是%p\n”,parray++); //打印的是指针数组第一个元素地址
printf(“第二个元素的地址是%p\n”,parray++); //打印的是指针数组第二个元素地址
printf(“第三个元素的地址是%p\n”,parray++); //打印的是指针数组第三个元素地址
1.若要遍历来查看指针数组的地址:
int *parray ; parray = &array[0]; for(i=0;i<3;i++){ printf("%d",*parray); //也可以写成printf ("%d",parray[i]); }
案例一:指针数组函数的综合的案例:
#include//初始化数组函数void initscores(int *array,int size){int i; for(i=0;i<size;i++){ printf("请输入第%d个学生成绩\n",i+1); scanf_s("%d",array); if(*array<0 || *array>100){ //在双条件判断的时候用 ”||”(或) printf("输入成绩错误,请重新输入\n"); exit(-1); } }}//打印数组函数void scoreprint(int *array,int size){int i;for(i=0;i<size;i++){ printf("请输入第%d个学生成绩为%d\n",i+1,*array++);}}//找到最高分int Maxvalue(int *array,int size){int j;int max = *array;for(j=0;j<size;j++){ if(max < *array){ max = *array; } array++;}printf("最高分是%d\n",max);}//找到最低分int Minvalue(int *array,int size){int j;int min = *array;for(j=0;j<size;j++){ if(min > *array){ min = *array; } array++;}printf("最低分是%d\n",min);}//算出平均分void average(int *array,int size){int add = 0;float average;int i;for(i = 0 ; i<size; i++){ add +=*array;}arrayage=(float)add / 10;printf("平均值为%d",average);} int main(){ //定义数组 int scores[10]={0}; int len = sizeof(scores) / sizeof(scores[0]); //初始化数组 intitscores(scores,len); //打印数组 scoreprint(scores,len); //找到最高分 Maxvalue(scores,len); //找到最低分 Minvalue(scores,len); //算出平均分 average(scores,len); return 0;}
指针的数组——好多指针放在一起,是一个数字,数组的每一个元素都是指针。
白话:好多变量的地址的集合
int array[3]; //多个整数,叫做整数数组
2.定义指针数组:
int *parray[3];
//多个指针,叫做指针数组
//数组中的每一项都是一个指针变量 指针变量是存放地址的变量
int a=2; int b=3; int *parray[3]; parray[0]=&a; parray[1] = &b;int i;for(i=0;i<30;i++){ printf("%d",*(parray[i]));}
九、数组指针:
定义数组指针: int (*p)[3]; //数组的指针
给数组指针赋值:p =a;
偏移值:由于它是数值指针,每次偏移是偏移一个数组 int(*p)[3]++ : 是偏移了3x4 = 12个单位
数组的指针,强调的是类型,数组的个数,偏移值是偏移了整个数组的大小。运用在二维数组。
int main(){int a[3]={1,2,3};int *p; //此指针并非是数组指针,仅仅是一个普通的整型数的指针,刚好指向了数组的首元素地址p=a;int i;for(i=0;i<3;i++){ printf("%d",*p++);}}
十、函数指针
1. 如何定义一个函数指针?
void(*p)( );
类型(*指针变量名)(函数参数); 如:int (*p)( int x , int y);
1.如何表示指针: * 2.如何知道是函数:() 3.函数指针是专用的,格式要求很强(参数类型 ,个数 ,返回值) ,就像数组指针一样
2. 如何给函数指针赋值?
函数名就是地址
void printWelcome(){ printf("欢迎来到函数指针学习课堂\n");}int main(){void *p();p = printWelcome; //函数就是地址 ,就像数组一样,数组名就是地址}
3. 如何通过函数指针调用函数?
p( ); //直接通过 名字( );
(*p)( ); //取内容(*指针名字) ( )
2. 用指向函数的指针作函数参数:
指向函数的指针变量的一个重要用途是把函数的地址作为参数传递到其他函数
如: void fun ( int (x1)(int x) , int (x2)(int x ,int y));
3. 返回指针值的函数
类型名函数名(参数)
int *p( )
十一、无类型指针(void) 无类型&&malloc
//正常数组定义
int main(){int *a=(int *)malloc(3*sizeof(int)); //也是数组int i;for(i=0;i<3;i++){ a[ i ]=i;}for(i=0;i<3;i++){ printf("%d",a[ i ] );}}......................................................................int main(){int n;printf("请输入整型数组元素的个数\n");scanf("%d",&n);int *parray = (int *)malloc(n*sizeof(int)); //数组if(parray == NULL){ printf("开辟空间失败");}int i;for(i=0;i<n;i++){ printf("请输入第%d个学生的成绩:",(i+1)); scanf("%d",&parry[i]);}for(i=0;i<n;i++){ printf("第%d学生的成绩:",(i+1),*parray[i]);}}
无类型的指针 :一个指针变量 不知道指向的空间是什么属性
十二、关于malloc的面试问题:
1.内存泄漏:
程序刚跑起来,很好,跑了几个小时,或者几天,或者几周,程序就崩溃了! malloc申请的空间,程序不会主动释放,linux中的话,程序结束后,系统会回收这个空间。
如何避免:
1.注意,循环中有没有一直申请
2.及时合理的释放free§; p=NULL;
野指针:
1.int *p = NULL; //这是正常的指针定义
2.int *p; //这是野指针
2.malloc如何使用?
指针变量 = (强制类型)malloc(大小)
如:int *p = (int *)malloc (3 * sizeof ( int ) ); //也是一种数组的定义方式
free(指针变量名);
free是释放内存空间的函数,通常与申请内存空间的函数malloc()结合使用,可以释放由malloc(); 、calloc();、realloc();等函数申请的内存空间。
十三、 指针收官 !!!!!!
1. 定义整型变量:
int a;
2. 定义p为指向整型数据的指针变量:
int *pa;
3. 定义整型数组 p,它由4个指向整型数据的指针元素组成;
int *pa[4]; //指针数组4. p为指向包含4个元素的一维数组的指针变量:
int (*p)[4]; //数组指针5. f为返回整型函数值的函数:
int f( );6. p为返回一个指针的函数,该指针指向整型数据:
int *p( );7. p为指向函数的指针,该函数返回一个整型值:
int (*p)( );8. p是一个指针变量,它指向一个指向整型数据的指针
int **p;9. p是一个指针变量,基类型为void(空类型),不指向具体的对象 :
void *p;