指针
指针==地址
变量有两种访问方式:
1.变量名 2.地址
#include <stdio.h>
int main()
{
int a = 10;
printf("a=%d\n",a);
printf("a的地址为:%p\n",&a);
printf("a=%d\n",*(&a)); //*为取值运算符,作用是把后面跟的内存地址中的数据“取出来”
return 0;
}
指针变量==存放地址的变量
#include <stdio.h>
int main()
{
int a = 10;
int *p; //* 是一个标识符,告诉系统我是一个系统变量,是用来保存地址的和下方的运算不同
P = &a;
printf("变量名访问a:\%d\n",a);
printf("a的地址是:0x%p\n",&a);
printf("地址访问a:%a\n",*(&a)); //取值运算符,他把后面跟的内存地址中的数据“取出来”
printf("指针变量的方式访问a:%d\n",*p);
return 0;
}
指针变量访问的两种方式:
直接访问:直接按变量名进行访问;
间接访问:将变量i的地址放在另一个变量中,然后通过该变量找到i的地址,从而访问i。
那既然指针变量是存放别人地址的变量,为什么区分类型呢?
#include <stdio.h>
int main()
{
int a = 0x1234;
int *p = &a;
char *c = &a;
printf("p = %p\n",p);
printf("c = %p\n",c);
printf("a = %x\n",*p); //取值的时候出了问题,取值运算符会根据指针变量类型,访问不同大小的空间
printf("a = %x\n",*c);
return 0;
}
决定指向空间的大小;
决定增量。
为什么需要用指针
练习1:封装一个函数,实现两数的交换。
以前的做法:
#include <stdio.h>
int main()
{
int data1 = 10;
int data2 = 20;
int tmp;
printf("交换前:data1=%d,data2=%d\n",data1,data2);
tmp = data1;
data1 = data2;
data2 = tmp;
printf("交换后:data1=%d,data2=%d\n",data1,data2);
return 0;
}
函数封装:
#include <stdio.h>
void changeData(int data1,int data2)
{
int tmp;
tmp = data1;
data1 = data2;
data2 = tmp;
}
int main()
{
int data1 = 10;
int data2 = 20;
printf("交换前:data1=%d,data2=%d\n",data1,data2);
changeData(data1,data2);
printf("交换后:data1=%d,data2=%d\n",data1,data2);
return 0;
}
但并不能成功改变数值,调用的函数里的data内存地址和主函数里的并不一样
用指针简介访问:
#include <stdio.h>
void changeData(int *pdata1,int *pdata2)
{
int tmp;
tmp = *pdata1;
*pdata1 = *pdata2;
*pdata2 = tmp;
}
int main()
{
int data1 = 10;
int data2 = 20;
printf("交换前:data1=%d,data2=%d\n",data1,data2);
changeData(&data1,&data2);
printf("交换后:data1=%d,data2=%d\n",data1,data2);
return 0;
}
练习2:指针指向固定区域
#include <stdio.h>
int main()
{
int a = 10;
printf("地址是:0x%p\n",&a);
int *p = (int *)0x000000000061FE10;
printf("p = 0x%p\n",&p);
return 0;
}
通过指针引用数组:
1.定义一个指针变量指向数组:指向数组首元素的地址
int a[10] = {1,2,3,4,5,6,7,8,9,10};//定义a为包含十个整型数据的数组
int *p; //定义p为指向整型变量的指针变量
p = &a[0]; //把a[0]的元素地址赋值给指针变量p
在C语言中,数组名(不包括形式参数组名,形参数组并不占实际的内存单元)代表数组中首元素的地址。因此,下面两个语句等价
p = &a[0]; //p的值是a[0]的地址;
p = a; //p的值是数组a首元素的地址(即a[0])
#include <stdio.h>
int main()
{
int arr[3] = {1,2,3};
int *p;
p = &arr[0];
//p = arr;
printf("数组的首元素是:%d\n",*p);
return 0;
}
2.指针的增量和数组的关系
#include <stdio.h>
int main()
{
int arr[3] = {1,2,3};
int *p;
p = &arr[0];
//p = arr;
printf("数组的第0个元素是:%d\n",*p);
printf("数组的第1个元素是:%d\n",*(p+1));
printf("数组的第2个元素是:%d\n",*(p+2));
return 0;
}
p+1不是内存代表的数据加了1,而是地址偏移了1个类型的字节数,是整型数偏移4个字节,是char型数偏移了一个字节。
#include <stdio.h>
int main()
{
int arr[3] = {1,2,3};
int *p;
p = &arr[0];
for(int i = 0;i<3;i++){
printf("地址是:%p,%d\n",(p+i),*(p+i));
}
return 0;
}
指针可当作数组名,下标法访问
p[i];可以访问数组中对应的数据
#include <stdio.h>
int main()
{
int arr[3] = {1,2,3};
int *p = arr;
for(int i=0;i<3;i++){
printf("%d",p[i]);
}
return 0;
}
练习:指针配合函数封装和数组
#include <stdio.h>
void initArry(int *parr,int size)
{
int i;
for(i=0;i<size;i++){
printf("请输入第%i个元素的数据: \n",i+1);
scanf("%d",&parr[i]); //scanf("%d",parr);
//parr++ 也可以
}
}
void printArry(int *parr,int size)
{
int i;
for(i=0;i<size;i++){
printf("%d ",parr[i]); //printf("%d ",*parr);
//parr++;
}
}
int main()
{
int arry[5];
int size = sizeof(arry)/sizeof(arry[0]);
initArry(arry,size);
printArry(&arry[0],size);
return 0;
}
练习2:将数组中的n个元素逆序存放
#include <stdio.h>
void initArry(int *parr,int size)
{
int i;
for(i=0;i<size;i++){
printf("请输入第%i个元素的数据:\n",i+1);
scanf("%d",&parr[i]);
}
}
void revangeArry(int *parr,int size)
{
int i,j;
int tmp;
for(i=0;i<size/2;i++){
j = size-1-i;
tmp = parr[i];
parr[i] = parr[j];
parr[j] = tmp;
}
}
void printArry(int *parr,int size)
{
int i;
for(i=0;i<size;i++){
printf("%d ",parr[i]);
}
}
int main()
{
int arry[5];
int size = sizeof(arry)/sizeof(arry[0]);
initArry(arry,size);
printArry(&arry[0],size);
revangeArry(arry,size);
printArry(&arry[0],size);
return 0;
}