在之前的文章中我们已经知道了指针的概念,指针就是一个变量,用来存放地址,地址指向唯一一块内存空间。指针的大小是固定的4/8个字节(32为机器/64位机器)。指针是有类型的,指针的类型决定了指针加减整数的步长,也指定了该指针在解引用操作时候的权限。
1、字符指针
字符指针的标识:char*,一般的使用方式如下:
int main()
{char ch = 'w';char *pc = &ch;*pc = 'w';//通过解引用地址进行修改return 0;
}
还有一种常见的使用方式:
int main()
{char* pstr = "hello world.";printf("%s\n", pstr);return 0;
}
注意:上面的赋值方式并非将整个字符串赋值给pstr,而是将"hello world."的首字符‘h’的地址存放在指针变量pstr中。说到这里可以看一道笔试题:
#include <stdio.h>
int main()
{char str1[] = "hello world.";char str2[] = "hello world.";char *str3 = "hello world.";char *str4 = "hello world.";if(str1 ==str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if(str3 ==str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}
程序的运行结果为:
为什么会出现这样的结果?
str1和str2为两个数组,这两个数组的数组名为数组首元素的地址。在创建数组时候,程序会在内存中开辟两个空间用于存放这两个字符串,也可以理解成对数组进行初始化,虽然内容一样,但表示完全不同的两个东西。
再来看一下str3和str4,它们属于两个字符类型的指针变量。它们指向的内容为"hello world."这个字符串,"hello world."本身是一个常量字符串,存储在内容中的静态区中。str3和str4均指向静态区中的同一个常量字符串,所以str3和str4的值是相同的。
2、指针数组
提到指针数组,不得不想起数组指针。这两个概念经常使得初学者晕头转向。让我们来慢慢分析。指针数组本质上是一个数组,就像漂亮美女的本质是美女而不是漂亮,如果实在理不清楚,就请记住最后两个字最重要!!那么,是不是就明白指针数组的本质就是数组了呢?
所谓指针数组,就是一个数组,该数组存放的元素的类型为指针类型,具体是何种指针还要具体分析,举一组例子:
int* arr1[10]; //整形指针的数组
先来找数组名arr1,根据操作符的优先级,arr1先和后面的中括号结合形成arr1[10],此时很明确,arr1[10]表示一个能存放十个元素的数组,那么存放的数据是什么类型呢?让我们回头看还剩下int* ,那么就说明arr1[10]中存放的元素为int* 类型的数据。
再简单地复述一遍,arr1是一个能存放10个整型指针变量的数组。
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组
再来看上面的这两个例子,arr2是一个能存放4个字符指针类型变量的数组。arr3是一个能存放5个二级字符指针的数组。现在感觉怎么样?是不是很清晰明了!
3、数组指针
高个子男孩本质是男孩而不是高个子,那么数组指针本质就是指针了。数组指针就是指向数组的指针,再重复一遍,这个指针指向的对象是一个数组。让我们来看一个数组指针。
int (*p2)[10];
还是同样的道理,上来先看变量名p2,p2被括号与*包起来,所以p2首先是一个指针。是指针总有一个类型,拿掉(*p2)剩下的int [10]就是这个指针的类型。这个类型说明这个指针指向的对象是一个含有10个整形元素的数组。
再来复述一遍:p2是一个指向含有10个整型元素数组的指针。
4、数组参数、指针参数
4.1一维数组传参
#include <stdio.h>
void test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int *arr)//ok?
{}
void test2(int *arr[20])//ok?
{}
void test2(int **arr)//ok?
{}
int main()
{int arr[10] = {0};int *arr2[20] = {0};test(arr);test2(arr2);
}
要保证传参时不发生错误,就是要保证在传递的值和接收的值为同一个类型。就好比在古代的几品的官员就要做对应品级的轿子,这是一个道理。我们来看test()函数中传递了一个数组名arr,数组名是数组首元素的地址,也就是说arr是一个整型数据的地址,那么arr就应该是int*类型,在接受参数时,可以直接写int arr[],当然int* arr也是没有任何问题的。
对于test2函数, int *arr2[20]是一个指针数组,arr2表示数组首元素的地址,也就是说arr2是一个整型指针的地址,那么arr2就是一个二级指针。在传递参数时可以直接使用int *arr[20],当然也可以使用int** arr来接收参数。
4.2、二级指针传参
#include <stdio.h>
void test(int** ptr)
{printf("num = %d\n", **ptr);
}
int main()
{int n = 10;int*p = &n;int **pp = &p;test(pp);test(&p);return 0;
}
有一句歌词唱得好,客人来了有美酒,豺狼来了有猎枪。同样的道理,传递什么类型的数据就使用什么类型的数据来接收。
5、函数指针
函数指针本质也是一个指针,指针指向的内容为函数。
void (*pfun1)();
同样的分析方法,pfun1和*被括号包起来,表名pfun1为一个指针,拿走它剩下void ()表明这个指针指向的内容为一个返回值为void类型的函数。