实例1
#include <stdio.h>
int main(void)
{
int a = 23;
int *p; // 定义了一个int型的指针变量
p = &a; //相当于p =(&a),p中存的是变量a的地址
*p = 111; //相当于a = 111
printf("a=%d.\n", a);
pirntf("*p=%p.\n", p);
return 0;
}
知识点:
(1)符号含义
| 符号 | 含义 |
|---|---|
| a | 代表变量a本身 |
| p | 代表指针变量p本身 |
| &a | 代表变量a的地址值 |
| *p | 代表指针变量品所指向的那个变量,也就是a |
| int *p | 定义指针变量p |
| %p | 用于打印指针变量的值 |
(2)指针定义的两种理解
int *p*
第一种理解:首先看到p,这个是变量名,其次,p前面有个,说明这个变量p是一个指针变量,最后,p前面有一个int,说明这个指针变量p所指向的是一个int型数据。(推荐,符合编译器设计思维)
第二种理解:首先看到p,这个是个变量名,其次,看到p前面的int *,把int *当作一个整体来理解,int *是一种符合类型。该类型表示一种指向int型数据的指针。
实例2
#include <stdio.h>
int main(void)
{
int a[5] = {555, 444, 333, 222, 111};
int *p;
//p = &a; //编译报警告,但是执行结果是对的,555。
//p = &a[0]; //相当于p = &(a[0]);编译没错也没警告,执行也没错,555
p = a; //编译没错也没警告,执行也没错,555
printf("*p = %d.\n", *p);
//a = p; //编译报错,因为数组名是个常量,所以不能赋值,所以数组名不能做左值。
return 0;
}
知识点:
(1)数组名与&a
数组名a做右值时,数组名表示数组首元素的首地址,所以可以直接赋值给指针。&a表示数组的首地址。数组首元素的首地址和数组的首地址是不同的。前者是数组元素的地址,后者是数组整体的地址。两个东西的含义不同,但数值上是相同的。
(2)访问数组两种方式
数组的方式依次访问:a[0]、a[1]、a[2]、a[3]、a[4]
指针的方式依次访问:p、(p+1)、(p+2)、(p+3)、(p+4)
因为p的访问方式已经确定是以几个字节几个字节去访问的。
(3)指针与++、--符号进行运算
指针本身也是一种变量,因此也可以进行运算,但是因为指针变量本身存的是其他变量的地址,因此该值进行、/、%等运算是无意义的。两个指针相加本身也是无意义的,相减有意义。指针变量+1、-1是有意义的。+1代表指针所指向的格子向后挪一格,-1代表指针所指向的格子向前挪一格。
(4)p++、++p、(p)++、++(p)
++先跟p结合,但是因为++后置的时候,本身含义就是先运算后增加1(运算指的是p++整体与前面的进行运算;增加1指的是p+1),所以实际上p++符号整体对外表现的是p的值,运算完成后p再加1。
所以p++等同于:p; p += 1;
++p,等同于p += 1; p;
(p)++,使用()强制将与p结合,只能先计算p,然后值加1。
++(*p),值加1,再代入运算。
--与++类似。
实例3
不改变实参
int add(int a,int b)
函数传参使用了int型数,本身是数值类型,实际调用该函数时,实参将自己拷贝一份,并将拷贝传递给形参进行运算。实参自己实际是不参与的。所以,在函数中,是没办法改变实参本身的。
改变实参
经典例子——交换两个数的值
#include <stdio.h>
int main(void)
{
int x,y;
x = 5;
y = 3;
printf("before swap:x = %d, y = %d.\n", x,y);
swap_pointer(&x, &y);
printf("after swap:x = %d, y = %d.\n", x,y);
}
int swap_pointer(int *p1, int *p2)
{
int temp;
temp = *p1; //实际调用时,p1得到的实参是x的地址&x,*p1代表的就是x
*p1 = *p2;
*p2 = temp;
return 0;
}