先来讲一下本人学指针的经历:大一的时候刚接触c语言对指针这东西真的是太迷了,感觉麻烦难懂不想其他语言一样。但是搞懂以后就被指针的魅力吸引甚至喜欢上c语言。不多讲,开始!(文章可能有些长,但放心全是基础的东西,里面有实际的例子。)
理解变量的存储
int main()
{
int a = 4;
printf("%d\n", a);
printf("%p", a);
return 0;
}
结果:
4
00000004
(1)int a;
c语言在内存的存储是以栈的形式。在栈中先定义了一个变量a并在内存中开辟了大小为4个字节的空间。然后让a指向这片空间。此时小宝贝就有了自己的空间了,就可以放东西了,耶!
(2)a=4;
此时将4的值赋就是将4存到a的那片空间中。
由以上代码可知,第一个输出的是存放的值,第二个输出的是a空间的地址。
但是我们通常是不直接这样给变量赋值,往往是手动输入:
scanf("%d",&a);
用户先输入一个int型的值,&a先找到自己的那片空间(&是取地址符),然后经值转化为二进制存入到这个空间里。(嘿嘿,一个宝藏就这样存了进来)
找到宝藏的法宝——指针
既然有了自己的空间又有了值,那谁能知道我的地址来发现我的宝藏呢?哈哈,指针来了。
他来了,他来了,他真的来了,,,,,,,
首先要知道,指针指向的是地址,是地址,是地址!不要误以为他指的的是变量的值。
指针变量的定义与赋值:
第一种形式:
int *p=&a;
第二种形式:
int *p;
p=&a;
int *p;这里要区分,int*是在一起的,代表指针类型,p指的是指针变量。
多级指针
指向指针的指针,有时人们也管它叫多维指针。既然指针变量是一个变量,指针变量能存变量的内存的地址。
像 int * 存 int 型变量的地址,char * 存 char 型的地址,那指针理所当然可以存指针变量的地址啊。
例如,int ** 存 int * 的地址,int *** 存 int ** 的地址。
这就是一个二级指针存一级指针的地址,三级指针存二级指针的地址,人们把这样的过程叫指向指针的指针,但其实也就是一个上一级的指针存了下一级的指针的地址而已。
因此,像上面说的,你存了它的地址,你就是指向它,所以:
二级指针存一级指针的地址,那么可以说二级指针指向一级指针
三级指针存二级指针的地址,那么可以说二级指针指向一级指针
多级指针用处多多。
唉,怎么说呢,本人也是刚学c语言没多久,能力也有限,只是有自己的理解,例子还是请大家去实践。
指针的应用
1.作为参数的指针(指针变量作为函数参数):我们都知道在使用自定义函数时,每个自定义函数与主函数之间联系都是通过值传递的形式,但是并不能通过在自定义函数中改变参数的值来改变主函数中参数的值。但是通过指针,就能在自定义函数中访问主函数的变量了。
简单的例子:
void fun(int *p);
int i=0;fun(&i)//因为自定义函数形参是指针,所以调用函数时传入地址。
这样在自定义的函数中就可以通过这个指针访问外面这个i
看几个代码的例子:
(1)不能通过在自定义函数中改变参数的值来改变主函数中参数的值:
voidchange(intp){printf("%d\n",p);//接受的值为5p=6;//想要改变参数的值}intmain(){intp=5;change(p);printf("%d\n",p);return0;}结果:55//值并没有发生改变
(2)利用指针后:
void change(int *p)
{
printf("%d\n", *p);//接受的值为5
*p= 6;//通过指针访问值,把p的值改为6
}
int main()
{
int p=5;
change(&p);//传入地址
printf("%d\n", p);
return 0;
}
结果:
5
6
//主函数的值发生改变
再看一个例子:利用自定义函数来比较三个数的大小
#include<stdio.h>
//交换
void swap(int* p1, int* p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
//compare
void compare(int* p1, int* p2, int* p3)//定义指针变量,利用指针和主函数中的变量联系
{
if (*p1 > * p2)swap(p1, p2);
if (*p1> * p3)swap(p1, p3);
if (*p2> * p3)swap(p2, p3);
}
int main()
{
int* p1, * p2, * p3, a, b, c;
scanf_s("%d,%d,%d", &a, &b, &c);
p1 = &a;//指针变量接收地址
p2 = &b;
p3 = &c;
compare(p1, p2, p3);//自定义函数指针接收的仍是地址
printf("%d,%d,%d", a, b, c);
return 0;
}
2.双胞胎——指针还是数组?(用数组名做函数参数):
首先必须了解一个基本知识。
大家都知道一个数组有多个变量,那么如何访问数组中的变量(那么多宝藏怎么找啊)。数组是一个连续的空间,只要将首元素的地址赋给指针,指针通过首元素的地址访问到了数组的首元素,那么通过遍历的方法不就访问到了整个数组。(就像顺腾摸瓜一样)
赋值方式:
int *p;
p=&a[0];
//或者利用元素名:
int *p;
p=a;//a=&a[0]
先看下列伪代码:
代码一
void fun(int arr[],int n )
'''''''
''''''
int main()
int array[10]=,,,,
,,,,,,,
fun(array,10)
代码二
void fun(int *arr,int n )
'''''''
''''''
int main()
int array[10]=,,,,
,,,,,,,
fun(array,10)
这两个伪代码是等价的,即数组名作为函数参数时可以当做是指针。
原理嘛,允许我偷下懒哈哈,况且比我讲的明白,(接图):
代码实例:
逆序输出数组中的数
void reversed(int a[], int n)//数组作为指针变量接收地址,int a[]等价于int *a
{
int i, j, m = (n - 1) / 2,temp;
for (i = 0; i <= m; i++)
{
j = n - 1 - i;//控制序列j
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
for (int i = 0; i < 5; i++)
printf("%d\t", a[i]);//利用指针访问元素
}
int main()
{
int a[5];
int n = 5;
for(int i = 0; i < 5; i++)
{
scanf_s("%d,", &a[i]);
}
for (int i = 0; i < 5; i++)
{
printf("%d\t", a[i]);
}printf("\n");
reversed(a, n);//数组名作为地址对函数进行调用
}
比较数组中数字的大小
void compare(int a[],int len,int *min,int *max)
{
int i;
*min =*max=a[0];
for (i = 1; i < len; i++)
{
*max = a[i] > *max ? a[i] : *max;
*min = a[i] < *min ? a[i] : *min;
}
}
int main()
{
int a[] = {1,2,3,4546,7,3,2,1,89,334};
int i;
int len = sizeof(a) / sizeof(a[0]);//数组的长度
int min, max;
compare(a,len,&min,&max);
printf("min=%d,max=%d", min, max);
return 0;
}
3.二维数组元素的地址
首先要明白的一点就是二维数组其实就是一维数组。在普通的一维数组中(a[0]),用数组名a作为数组a[0]的地址,那么在二维数组中(a[3][4]),a[0],a[1],a[2]就表示数组第一个元素的地址。这个结合一下实例可能比较好理解一下
代码实例
以a[0]作为元素地址
int main()
{
int a[3][4] = {12,2,3,4,56,7,8,9,10,1,9,34};
//int n = 5;
int* p;
for(p=a[0]; p<a[0]+12; p++)//a[0]作为数组的地址传递给指针p。a[0]+12是最后一个元素的地址
{
if ((p - a[1]) % 4 == 0)
printf("\n");
printf("%d\t", *p);
}
return 0;
}
结果:
12 2 3 4
56 7 8 9
10 1 9 34
E:\vs\c++\h\Debug\h.exe (进程 12316)已退出,代码为 0。
按任意键关闭此窗口. . .
若以a[1]作为元素地址
int main()
{
int a[3][4] = {12,2,3,4,56,7,8,9,10,1,9,34};
//int n = 5;
int* p;
for(p=a[1]; p<a[1]+8; p++)
{
if ((p - a[1]) % 4 == 0)
printf("\n");
printf("%d\t", *p);
}
return 0;
}
结果:
56 7 8 9
10 1 9 34
E:\vs\c++\h\Debug\h.exe (进程 21144)已退出,代码为 0。
按任意键关闭此窗口. . .
以a[2]作为元素地址:
int main()
{
int a[3][4] = {12,2,3,4,56,7,8,9,10,1,9,34};
//int n = 5;
int* p;
for(p=a[2]; p<a[2]+4; p++)
{
if ((p - a[1]) % 4 == 0)
printf("\n");
printf("%d\t", *p);
}
return 0;
}
结果:
10 1 9 34
E:\vs\c++\h\Debug\h.exe (进程 19664)已退出,代码为 0。
按任意键关闭此窗口. . .
由此可得如图的结构:
所以,在应用多维数组变量时应将多维数组看作一维数组来解决就容易很多了。
以上就是我对指针的部分理解,当然还有很多,当然存点小私心写得都是我原来不懂得哈哈。真的很有意思整懂了以后。希望有用。
网友评论