我使用VS CODE+MSYS2的编译环境进行学习,想使用VS CODE进行C/C++代码编写的小伙伴参考这篇文章进行环境配置VS Code 配置 C/C++ 编程运行环境(保姆级教程)
一、指针的引入
指针==地址
#include <stdio.h>int main() {int a = 10;printf("The value of a is: %d\n", a);printf("The address of a is: %p\n", &a);printf("The value of a is: %d\n", *(&a));//取值运算符,把后面内存地址内的数据“取出来”return 0;
}
变量:int a=10; (四要素:类型int、变量名a、内存地址、值10)
变量访问的两种方式:
1、通过变量名访问:
printf("The value of a is: %d\n", a);
2、通过地址访问:
&取地址运算符 *将地址内的值读出运算符printf("The value of a is: %d\n", *(&a));
二、指针变量的引入
指针变量==存放地址的变量
#include <stdio.h>int main() {//什么是整型变量,存放整型数的变量//什么是字符型变量,存放字符型数据的变量//什么是指针变量,存放指针的变量//指针==地址:指针变量就是存放地址的变量int a = 10;int *p;//这里*是一个标识符,告诉系统我是一个指针变量,用来保存别人的地址,和14行运算符不同p=&a;//p=a的地址printf("The value of a is: %d\n", a);printf("The address of a is: %p\n", &a);printf("The value of a is: %d\n", *(&a));//取值运算符,把后面内存地址内的数据“取出来”printf("pointer-The value of a is: %d\n", *p);return 0;
}
如何定义一个指针变量—— * 的标识作用——只用于指针变量定义或者声明的时候
如何使用一个指针变量—— * 的运算作用——把地址内的数据取出
#include <stdio.h>int main() {int a = 0x1234;int *i = &a;char *c = &a;printf("*i:a=%x\n", *i);printf("*c:a=%x\n", *c);printf("*i:addr=%p\n", i);printf("*c:addr=%p\n", c);printf("++i=%p\n", ++i);printf("++c=%p\n", ++c);
}
int类型占用4个字节(byte),一个字节占用8位(bit)————32bit
char类型占用1个字节,一个字节占用8位————8bit
三、为什么要使用指针
1、场景一之变量值交换
#include <stdio.h>int main(){int a=10;int b=20;int temp; printf("before:");printf("a=%d\t",a);printf("b=%d\n",b);temp=a;a=b;b=temp;printf("after:");printf("a=%d\t",a);printf("b=%d\n",b);return 0;
}
当我们想把main函数里面的值交换封装到函数里面却发现交换后的a和b的值并没有改变
#include <stdio.h>void changeData(int a,int b){int temp;temp=a;a=b;b=temp;
}int main(){int a=10;int b=20;printf("before:");printf("a=%d\t",a);printf("b=%d\n",b);changeData(a,b);printf("after:");printf("a=%d\t",a);printf("b=%d\n",b);return 0;
}
原因是应为数据发生交换的内存空间和main函数里变量的内存空间不在同一内存空间 ,解决办法将changeData函数的参数变为指针,调用changeData函数时将变量a和b的地址传入
#include <stdio.h>void changeData(int *a,int *b){int temp;temp=*a;*a=*b;*b=temp;
}int main(){int a=10;int b=20;printf("before:");printf("a=%d\t",a);printf("b=%d\n",b);changeData(&a,&b);printf("after:");printf("a=%d\t",a);printf("b=%d\n",b);return 0;
}
2、场景二之指针指向固定的内存地址
#include <stdio.h>int main(){unsigned int *p=(unsigned int *)0x0019FF11;printf("p = 0x%p\n",p);return 0;
}
四、通过指针引用数组
1、定义一个指针变量指向数组
在C语言中,数组名(不包括形参的数组名,形参数组并不占用实际的内存单元)和数组中的首元素都可以代表数组的首地址
2、指针偏移遍历数组
我们之前访问数组元素用的都是下标法printf("arr[0]=%d\n",arr[0]); 系统在使用数组下标对数组成员进行访问时开销比较大,指针的访问效率远远大于数组名的访问效率但普通工程代码量小影响微乎其微。
在数组中所有元素的地址是连续的,第一个元素是a,那么第二个就是a+1,第三个就是a+2......但这个1并不是数组一而是字节数,比如int类型的数组第二个元素就比第一个元素的地址多了四个字节(32位)参考本文 二、指针变量的引入理解
每次重新编译运行后数组的首地址都会改变,因为局部数组是放在栈区的,由编译器自动进行分配和释放
#include <stdio.h>int main(){int arr[3]={1,2,3};printf("arr address:%p\n",arr);printf("arr[0] address:%p\n",&arr[0]);int *p,*q;p=arr;q=&arr[0];printf("a[0]=%d\t",*(p));//指针变量p存放了数组的首地址,通过取值符号*将地址内的值取出printf("a[0] address:%p\n",p);printf("a[1]=%d\t",*(p+1));printf("a[1] address:%p\n",p+1);printf("a[2]=%d\t",*(p+2));printf("a[2] address:%p\n",p+2);printf("a[0]=%d\t",*(q)); printf("a[1]=%d\t",*(q+1)); printf("a[2]=%d",*(q+2)); return 0;
}
通过for循环遍历可节省代码量
#include <stdio.h>int main(){int arr[3]={1,2,3};int len=sizeof(arr)/sizeof(int);//或者int len=sizeof(arr)/sizeof(arr[0])printf("arr address:%p\n",arr);printf("arr[0] address:%p\n",&arr[0]);for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,arr[i]);}printf("\n\n");int *p,*q;p=arr;q=&arr[0];for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(p+i));printf("address=%p\n",p+i);}printf("\n");for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(q+i));printf("address=%p\n",q+i);}return 0;
}
3、指针当做数组名来用
4、指针常量和指针变量的区别
int *p是指针变量,它所保存的地址是可变的
数组名arr是指针常量,它的地址是确定的
#include <stdio.h>int main(){int arr[3]={1,2,3};int *p=arr;for(int i=0;i<3;i++){printf("%d ",*p++);}
/*for(int i=0;i<3;i++){printf("%d ",*arr++);//编译不通过,指针常量}
*/for(int i=0;i<3;i++){printf("%d ",*(arr+i));}printf("\n\n");return 0;
}
5、sizeof计算大小的区别
在32位操作系统中指针占4字节,64位操作系统中指针占8字节
6、小练习
(1)通过指针的方式实现数组的初始化和遍历
#include <stdio.h>void initArray(int *p,int len);
void printArray(int *p,int len);int main(){int arr[3];int len=sizeof(arr)/sizeof(int);initArray(arr,len);printArray(arr,len);return 0;
}void initArray(int *p,int len){for(int i=0;i<len;i++){printf("please enter %d number:",i+1);scanf("%d\n",p++);}
}void printArray(int *p,int len){for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(p+i));//printf("arr[%d]=%d\t",i,*p++)}
}
(2)实现数组翻转
#include <stdio.h>void Array1(int *p,int len);
void Array2(int *p,int len);
void printArray(int *p,int len);int main(){int arr1[5]={5,4,3,2,1};int arr2[6]={6,5,4,3,2,1};int len1=sizeof(arr1)/sizeof(int);int len2=sizeof(arr2)/sizeof(int);printf("before:\n");printArray(arr1,len1);printf("\n");printArray(arr2,len2);printf("\nafter:\n");Array1(arr1,len1);printArray(arr1,len1);printf("\n");Array2(arr2,len2);printArray(arr2,len2);return 0;
}void Array1(int *p,int len){int temp;for(int i=0;i<(len/2);i++){//前2个数,中间那个数不变for(int j=len-i-1;j<=len-i-1;j++){//后2个数/*形式1*/temp=p[i];p[i]=p[j];p[j]=temp;/*形式2*/// temp=*(p+i);// *(p+i)=*(p+j);// *(p+j)=temp; }}
}void Array2(int *p,int len){int temp;for(int i=0;i<=(len/2);i++){//前3个数for(int j=len-i-1;j<=(len-i-1);j++){//后3个数/*形式1*/// temp=p[i];// p[i]=p[j];// p[j]=temp; /*形式2*/temp=*(p+i);*(p+i)=*(p+j);*(p+j)=temp; }}
}void printArray(int *p,int len){for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(p+i));//printf("arr[%d]=%d\t",i,*p++)}
}