关于指针
先看一下和指针的第一次接触。
#include<stdio.h>
int main() {
int a = 3;
int b = 5;
int *a_p;
/*输出每一个变量的地址*/
printf("a:%p\n", &a);
printf("b:%p\n", &b);
printf("a_p:%p\n", &a_p);
/*将a的地址赋给a_p*/
a_p = &a;
printf("a_p:%p\n", a_p);
return 0;
}
在我这个环境下的输出结果是:
a:0061FF2C
b:0061FF28
a_p:0061FF24
a_p:0061FF2C
开始时,定义变量的时候为变量分配了地址。将a的地址赋值给指针变量a_p后,此时a_p的值为a的地址,此时如果通过a_p输出a的值,可得到:
printf("*a_p:%d\n", *a_p);
结果为:
*a_p:3
在我的环境中,声明的变量在内存中先是在地址为0061FF2C上保存值为3,然后在地址为0061FF28上保存值为5,然后在地址0061FF24上保存未赋值的指针a_p。
综上:指针就是记录内存中的一个存放数据的地址。根据这个地址可以找到想要的数据。
指针运算
指针运算指的是针对指针进行整数加减运算,以及指针之间进行减法运算的功能。
在C语言中,对指针进行加1运算,地址的值会增加当前指针所指向数据类型的长度。比如指针指向的类型为int,则在指针上加1,地址加4;指针加3,地址数值就加12;
空指针
空指针是指可以确保没有指向任何一个对象的指针。
通常使用宏定义NULL来表示空指针常量值。
空指针可以保证没有它和任何非空指针进行比较都不会相等。
(补充:NULL、0、\0三者比较
在C语言的标准中,空字符的定义为:所有的位为0的字节成为空字符。也就是说,空字符是值为0的字符。
空字符在表现上通常使用‘\0’。
一般来说,NULL的定义为:
#defne NULL 0
但是,如果在字符串的最后使用NULL,就必然会发生错误。标准允许将 NULL定义成(void*)0,所以在 NULL被定义成(void*)的时候,如果使用NULL来结束字符串,编译器必然会提示警告。
对于链表来说通常会在数据链的最后放置一个NULL来表示结束。)
指针运用例子
交换两个数:
第二个程序是采用宏定义实现的,书上说如果a等于b时,就不能正常运行,我没想明白。
#include<stdio.h>
#include<stdlib.h>
void swap(int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}
/*书上说这种交换方法当a和b一样的时候不可用,但是不知道为什么不可以*/
#define swap(a, b) (a += b, b = a - b, a -= b)
int main() {
int a = 2;
int b = 2;
swap(a, b);
printf("a = %d\nb = %d\n", a, b);
return 0;
}
数组与指针
数组名就是数组的首元素的地址。
访问数组成员的时候可以使用下标来表示,为什么还要用指针?因为,使用指针运算可以写出高效的程序。
在一个循环中会出现多次的array[i],每一次都要执行一次*(array + i),这样效率比较低。因此可以这样写:
for (p = &array[0]; p != &array[max]; p++) {
//这里使用*p进行各种各样的处理
}
其实效率并没有提升多少。
C语言是不能将数组作为函数参数进行传递的,但是你可以通过传递初始元素的指针来达到将数组作为参数进行传递的目的。
只有在声明函数形参时,数组的声明才可以被解读陈指针。比如对于 int fun(int a[]),编译器可以针对的解读成:int fun(int *a),即使定义了元素的个数编译器也是无视的。
在函数的声明时,以下几种情况都是一样的:
int fun(int a[]);
int fun(int *a);
int fun(int a[10]);