概述
C语言中的指针是专门用来存放内存地址的变量。每个指都有一个与之相关联的数据类型,该类型决定了指针指向的数据的类型。
C语言中使用*把一个标识符声明为一个指针,指针定义的一般形式为:
数据类型 *指针变量名;
例如:
char *pc;
int *pi;
doule *pd = NULL;
第三行定义了一个指针并初始化为NULL,表示该指针不指向任何变量。
注意:第一行和第二行定义的指针未初始化,这是相当危险的。因为未初始化的指针随机指向内存中一个地址,对该地址空间的写操作其后果不能确定,所以应避免使用未初始化的指针,在定义指针时最好将它初始化为NULL。
与指针相关的两个运算符:
& 取地址运算符
* 取指针指向的内存单元的值
指针和数组
数组名实际上就是指向数组第一个元素的指针。
例1:以不同方式输出数组所有元素的值
#include <stdio.h>
int main()
{
int a[10], i, *p = NULL;
for (i = 0; i < 10; i++)
a[i] = i;
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
for (i = 0; i < 10; i++)
printf("%d ", *(a + i));
printf("\n");
for (p = a; p < a +10; )
printf("%d ", *p++);
printf("\n");
return 0;
}
说明:表达式p++,++和的优先级相同,结合方式为自左向右,因此等价于*(p++)。
注意:不能对数组名执行++、–操作,比如a++是不合法的,因为a是数组的首地址,它的值在程序运行过程中是固定不变的,是常量。
数组元素也可以是指针类型,这种数组称为指针数组。
指针数组定义的一般形式为:
数据类型 *数组名[数组长度];
说明:*的优先级低于[]。
例2:指针数组和二级指针
#include <stdio.h>
int main()
{
int a[5] = {1, 3, 5, 7, 9};
/*int *pi[5] = {NULL, NULL, NULL, NULL, NULL}, i;*/
int *pi[5], i;
int **pp = pi;
for (i = 0; i < 5; i++){
pi[i] = &a[i];
printf("%d ", *pi[i]);
}
printf("\n");
for (i = 0; i < 5; i++, pp++)
printf("%d ", **pp);
printf("\n");
return 0;
}
例3:数组指针
#include <stdio.h>
void print_arr(int (*p)[])
{
int i;
for (i = 0; i < 5; i++)
printf("%d ", (*p)[i]);
printf("\n");
}
int main()
{
int a[2][5] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 0};
int (*p)[5] = a;
print_arr(p);
p++;
print_arr(p);
return 0;
}
注意:区别int (*p)[5]和int *p[5],前者是一个指针,指向包含5个元素的数组。后者是一个数组,长度为5,数组中每个元素指向一个整形变量。
指针和函数
指向函数的指针
指向函数的指针是一个指针变量,它指向一个函数。一个函数的函数名就是一个指针,它指向函数的代码。
指向函数的指针的一般定义形式为:
返回值 (*指针变量名) ()
注意:前者是返回指针的函数,它是一个函数声明。后者是指向函数的指针,它定义了一个指针。
int *f(int i, int j);
int (*f)(int i, int j);
函数指针作为形参
例4:函数指针作为形参
#include <stdio.h>
int get_max(int i, int j)
{
return (i > j? i : j);
}
int compare(int i, int j, int k, int (*p)(int, int))
{
int ret = 0;
ret = p(i, j);
ret = p(ret, k);
}
int main()
{
int ret = 0;
ret = compare(1, 3, 5, get_max);
printf("The max is %d.\n", ret);
return 0;
}
补充:信号处理函数将用到该知识点。
返回函数指针的函数
例5:返回函数指针的函数
#include <stdio.h>
int get_max(int i, int j)
{
return (i > j? i : j);
}
int (*get_function(int a))(int, int)
{
printf("The number is %d.\n", a);
return get_max;
}
int main()
{
int ret = 0;
int (*p)(int, int);
p = get_function(100);
ret = p(10, 15);
printf("The max is %d.\n", ret);
return 0;
}
说明:get_function函数返回了指向函数get_max的指针int(*)(int, int)。
字符指针和字符数组的区别
例6:字符指针和字符数组的区别
#include <stdio.h>
int main()
{
char string[] = "Linux C";
char *pc = "Linux C";
string[0] = 'A';
printf("%c\n", string[0]);
pc[0] = 'B';
printf("%c\n", pc[0]);
return 0;
}
上述代码的运行结果是:
# ./a.out
A
Segmentation fault (core dumped)
进程执行过程中提示“段错误”是因为指针pc指向的数据在内存空间中是只读(这些数据存放在.rodata段)的。