1. 前言
指针在很多书本上都是当做重点来介绍,作为C语言的灵魂,项目里指针无处不在。
比如: 指针作为函数形参的时候,可以间接修改源地址里的数据,也就相当于解决了函数return一次只能返回一个值的问题。
指针在嵌入式、单片机里使用最直观,可以直接通过指针访问寄存器地址,对寄存器进行配置;计算机的CPU、外设硬件都是依靠地址操作的。
2. 指针变量如何定义?
#include <stdio.h> #include <string.h> int main() { char *p1; //定义一个char类型的指针变量 int *p2; //定义一个int类型的指针变量 //int类型的指针变量: 存放地址数据。 int data=123; //定义一个int类型的变量 //int类型的变量: 存储整数数据。 return 0; }
3. 指针如何使用?
#include <stdio.h> #include <string.h> int main() { // &data 取地址 a&b 按位与 a&&b 并且 // int *p 定义一个int类型的指针 // *p 取出指针指向空间中的数据--取数据 // a*b a和b乘法 int *p; //指针变量本身就是存放地址的 int data=123; //p=data; //错误:data本身只是一个变量标识符,不是地址 p=&data; //将data的地址赋值给指针p printf("*p=%d\n",*p); //取出指针p指向空间中的数据 *p=666; //给指针指向的空间赋值 printf("data=%d\n",data); return 0; }
4. 什么是野指针?
野指针就是本身没有合法地址空间—非法指针。
野指针会导致的常见错误:段错误。
下面代码就会导致段错误:
#include <stdio.h> #include <string.h> int main() { int *p;//指针只能存放地址 *p=123; printf("*p=%d\n",*p); return 0; }
5. 指针本身占的空间是多少?
所有指针类型都占4个字节空间。和类型没有关系。
#include <stdio.h> #include <string.h> int main() { int *int_p;//指针只能存放地址 int int_a; char *char_p;//指针只能存放地址 char char_a; float *float_p;//指针只能存放地址 float float_a; double *double_p;//指针只能存放地址 double double_a; printf("int_a=%d\n",sizeof(int_a));//4 printf("int_p=%d\n",sizeof(int_p));//4 printf("char_a=%d\n",sizeof(char_a)); printf("char_p=%d\n",sizeof(char_p)); printf("float_a=%d\n",sizeof(float_a)); printf("float_p=%d\n",sizeof(float_p)); printf("double_a=%d\n",sizeof(double_a)); printf("double_p=%d\n",sizeof(double_p)); return 0; }
6. 指针访问数组成员
#include <stdio.h> #include <string.h> int main() { int a[]={1,2,3,4,5,6,7,8,9,0}; int *p; p=a; printf("下标4的值:%d\n",a[4]); //5 printf("下标4的值:%d\n",*(a+4)); //5 printf("下标4的值:%d\n",*(p+4)); //5 return 0; }
6.2 指针访问一维数据常用的操作方式:字符串
#include <stdio.h> #include <string.h> int main() { char str[]="1234567890"; char *p=str; int len=0; printf("p=%s,str=%s\n",p,str); //计算字符串的长度 while(*p++!='\0') { len++; } printf("len=%d\n",len); return 0; }
6.3 指针自增和自减?++和—运算符
#include <stdio.h> #include <string.h> int main() { int a[]={1,2,3,4,5,6,7,8,9,0}; int *p=a; printf("%d\n",*p); //1 printf("%d\n",*p++); //1 printf("%d\n",*p); //2 printf("%d\n",*(p+3));//5 printf("%d\n",*p);//2 printf("%d\n",*(++p));//3 printf("%d\n",*p);//3 printf("%d\n",*p--);//3 printf("%d\n",*p);//2 return 0; }
6.4 指针自增自减偏移字节是多少?
与指针本身的类型有关系。
#include <stdio.h> #include <string.h> int main() { /* int a[]={1,2,3,4,5,6,7,8,9,0}; int *p=a; printf("偏移之前的地址:p=%#x\n",p); *(p++); printf("%d\n",*p); //2 printf("偏移之后的地址:p=%#x\n",p); */ char a[]={1,2,3,4,5,6,7,8,9,0}; char *p=a; printf("偏移之前的地址:p=%#x\n",p); *(p++); printf("%d\n",*p); //2 printf("偏移之后的地址:p=%#x\n",p); return 0; }
6.5 数组本身可以当做指针使用吗?
不可以
指针特点: 自增、自减、可以改变指向。
#include <stdio.h> #include <string.h> int main() { int a[]={1,2,3,4,5}; //*(a+3) int b[]={11,12,13,14,15}; //下面3行代码是错误的 a--; a++; a=b; return 0; }
6.6 指针可以当做数组使用吗?
可以
数组特点: 可以通过下标访问数组成员。
#include <stdio.h> #include <string.h> int main() { int a[]={1,2,3,4,5}; int *p=a; printf("%d\n",a[0]); printf("%d\n",p[0]); //*p return 0; }
7. 数组指针
数组指针可以指向一个一维数组,行指针也叫一维数组指针。
定义语法:char (*p)[5];
该指针指向一个二维数组里的一个一维数组地址,一维数组的成员是5个字节。
二维数组的定义方法:char a[10][5];
#include <stdio.h> #include <string.h> int main() { int (*p)[5]; //定义一个一维数组指针---行指针 int a[2][5]= { {1,2,3,4,5}, {6,7,8,9,10} }; p=a; //将a地址给p指针 printf("%d\n",p[0][2]); p++; //加一个一维数组的大小 printf("%d\n",p[0][2]); return 0; }
8. 指针数组
指针数组: 表示该数组成员可以存放指针。
指针数组定义语法:int *p[5];
表示定义一个int数组,该数组的类型可以存放5个int类型的指针变量(地址)。
#include <stdio.h> #include <string.h> int main() { int a,b,c; int *p[3]; //一次定义3个int类型的指针变量 //存放地址 p[0]=&a; p[1]=&b; p[2]=&c; //对空间赋值 *p[0]=123; *p[1]=456; *p[2]=789; //取出数据 printf("%d\n",*p[0]); printf("%d\n",*p[1]); printf("%d\n",*p[2]); return 0; } #include <stdio.h> #include <string.h> int main() { char a[][100]={"小明","小白","小李"}; char *p[]={"小明","小白","小李"}; printf("%s\n",a[0]); printf("%s\n",p[0]); return 0; }
9. 指针类型常见的初始化值:NULL
#include <stdio.h> #include <string.h> int main() { char *p=NULL; // (void*)0 == NULL printf("%#x\n",p); if(p!=NULL) { //判断指针是否可以使用 } return 0; }