指针
指针作为C语言中极具代表性的特征之一,也是C语言学习中的一大难点。
简单来说,指针我们需了解的最基础的即:
- 指针是一个用来存放地址的变量,地址唯一标识一块内存空间。
- 指针的大小是固定的4/8个字节(32位平台/64位平台)。
- 指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
指针与数组传参
了解指针与数组的传参,首先了解传值调用和传址调用的问题
传值调用:除了数组,其他数据实参均以直接拷贝,以传值形式调用
传址调用:数组传参时不可直接拷贝,需降维为指针;但数据也可以进行传址调用,只要在它前面加上取地址操作符即可
在讲述这个问题之前,我们先看以下这段代码:
int main()
{
char str1[] = "hello.";
char str2[] = "hello.";
char *str3 = "hello.";
char *str4 = "hello.";
if(str1 ==str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 ==str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
以上一段代码的输出结果为"str1 and str2 are not same
" ,"str3 and str4 are same
"
因为str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当多个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。
指针和数组作为参数传入函数时,传入的是地址,即指向变量的地址和数组的首地址,可以在函数中改变指针或数组的值,但本质上还是值的传递(区别于变量的值传递的是:变量值传递不会改变实参原来的值。),我们无法对指针和数组的地址进行操作(如:地址赋值,分配内存等),要进行地址操作需要使用指针引用或二级指针。
一维数组传参
数组名作为函数参数传递时,传递数组首元素的地址,函数接收的实际为原参数的一份拷贝,使得函数操纵时不影响实际值
对于一维数组传参,有以下几种表示方法:
void test(int arr[])
void test1(int arr[10])
void test2(int *arr)
void test3(int *arr[20])
void test4(int **arr)
以上五种写法都是正确的
用数组接收传的是首元素地址,可以指定数组大小,也可以不指定,因为传到函数内的是地址,故可以用指针接收,第四种情况中,将一个指针数组的数组名传入,第五种则是传入指针数组数组名,代表首元素地址,首元素是一个指向数组的指针,再取地址,表示二级指针
调用函数时实际传递的是一个指针,即函数形参为指针,但数组名依然可被表示为数组首元素的地址被调用。两种调用明显用指针较为准确,因为实参实际是指针,而函数中一维数组可以不标明数组长度也是这个原因:函数没有给数组参数分配内存空间,形参指向已经开辟好的空间。指定数组长度,则数组作为一个显式参数传给数组
二维数组传参
二维数组的表示方法如下:
void test(int arr[3][5])
//void test(int arr[][])
void test(int arr[][5])
//二维数组传参,函数形参的设计只能省略第一个[]的数字
以上表示方法第二种有错误
从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,即多维数组传参要指定第二维或者更高维的大小,可以省略第一维的大小
一级、二级指针传参
一级指针传参和二级指针传参较为简单,传参后,对指针参数执行间接访问操作使函数修改原本变量的值,值得一提的是:
函数参数部分为一级指针时,函数可接收的参数有以下几种
- 一个整形指针
- 整型变量地址
- 一维整型数组数组名
函数参数部分为二级指针时,函数可接收的参数有以下几种
- 二级指针变量
- 一级指针变量地址
- 一维指针数组的数组名
- 二维数组的数组名
数组指针与指针数组
数组指针
定义
int (*p)[10];
//p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向
一个数组,叫数组指针。
数组指针的运用
void