C 指针&&数组
Posted _NiuLi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C 指针&&数组相关的知识,希望对你有一定的参考价值。
一、指针与数组的定义
首先来看一下定义与声明的具体含义
定义 | 只能出现一次 | 确定对象的类型并分配内存,用于创建新的对象(特殊的声明) |
声明 | 可以出现多次 | 描述对象的类型,用于说明其它对象的类型 |
我们常说数组名是数组首元素的地址,即是一个指针。有时候我们也会把数组名当做指针来访问数组;还有给函数传一个数组时传的是数组首元素的地址,函数的形参可以定义为一个指针变量。这是不是说数组名就与指针等价呢? 不是的!
来看下面的例子
1、定义数组声明为指针
来看一下下面的代码
新建两个源文件test_1.c test_2.c,将它们放到一个项目test中:
test_1.c:
char arr[]="abcdef";
test_2.c:
#include <stdio.h>
extern char *arr;
int main()
printf("%s\\n",arr);
return 0;
上面的代码会输出abcdef吗?答案是不会。如果运行这个程序时,编译器会报错。
这是为什么呢? 因为在test_2.c中编译器会把arr当做指针,但是在arr中存放的是"abcdef",任何存入指针变量的内容,编译器都会把它当做一个地址这时编译器会把arr数组的前四个字节的内容当做一个地址,即abcd的ASCII值,即61626364,假设计算机的存储模式是小端存储,此时arr的值为64636261,这是一个非法的地址,故编译器会报错。
那么,这个时候如果还想输出"abcdef",改怎么做呢?可以这样做:
printf("%s\\n",(char*)&arr);
将arr的地址取出来强制类型转换为char*,这是我们就拿到了数组arr的首元素的地址,就可以输出数组内容。
2、定义指针声明为数组
来看下面的代码:
test_1.c:
char *p="abcdef";
test_2.c:
#include <stdio.h>
extern char*p[];
int main()
printf("%s\\n",p);
return 0;
上面的代码输出的结果是什么呢?输出的并不是"abcdef",这是如果以%p输出p的值,p的值为00422fa4(不同的编译器输出的值不同),这是为什么呢?我们来分析一下。
在定义一个指针变量,并给它赋一个常量字符串时,在内存里会发生什么呢?如下图:
这时如果把指针变量声明为一个数组的话,编译器会把p的值当做一个数组,输出的值就是p的值。
这时,如果还想输出"abcdef",改怎么做呢?可以这样做:
printf("%s\\n",*(int*)p);
将p的值强制类型转换为int*,然后解引用访问到的就是的p值,也就是"abcdef"的首地址。
从上面的例子可以看出,指针和数组名并不完全等价。
二、指针数组与数组指针
1.指针数组
首先,指针数组是一个数组,数组元素是指针。
比如,int*p[2];这是定义一个数组,因为数组的元素是指针,所以称为指针数组。
由于[]的优先级高于*,所以arr先与[2]结合,即这是大小为2的数组,前面的是数组元素的类型,可以与int a[2]类比,int为数组元素的类型。
2.数组指针
首先,数组指针是一个指针,这个指针可以指向数组,所以称为数组指针。
比如,int (*p1)[2];这是定义一个数组指针变量。 *先与p1结合,所以p1是一个指针,去掉变量名为类型 int[2],即p1可以指向大小为2的 int型数组。可以与int *ptr类比,ptr是一个指针,去掉*ptr,为int,即ptr可以指向int类型数据。
我们来看一下下面的例子
#include <stdio.h>
int main()
int a[5][5];
int (*p)[4];
p = (int(*)[4])a;
printf( "%d,%p\\n", &p[4][2] - &a[4][2],&p[4][2] - &a[4][2]);
return 0;
上面的代码输出的结果是什么呢?答案是-4 和FFFFFFFC;
这是为什么呢?首先,我们要找到p[4][2]和a[4][2]的位置
p[4][2]与a[4][2]之间有4个元素,故&a[4][2]-&p[4][2]=4,输出的是4;
&p[4][2]-&a[4][2]=-4, - 4在内存中是以补码的形式存储的即FFFFFFFC,以%p输出就是FFFFFFFC。
三、数组的传参
我们知道给函数传一维数组时,传的是数组首元素的地址,函数的形参可以是指针变量,也可以把数组放到形参的位置。要注意的是传给函数的数组会降级为数组首元素的地址。
那么二维数组该如何传给函数呢?
如果将数组名传给函数,函数的形参应该定义为什么类型呢?
在这之前我们要对二维数组有一个深入的理解。
定义一个二维数组 int arr[2][5];这个数组在内存是如何存储的呢?
二维数组可以看作一个一维数组,只是这个一维数组的元素是一个数组。如上面的二位数组,可以看作一个一维数组 arr[2]=arr[0],arr[1]
那么如果把数组名传给函数,函数接首到的到底是什么呢?
我们知道数组名代表数组首元素的地址,这个二位数组的首元素是arr[0]的地址,即&arr[0]. arr[0]是一个数组,取出来的是数组的地址,类型为数组指针。所以函数的参数必须定义为数组指针类型。
如下代码所示:
#include <stdio.h>
void fun1(int arr[][5] ) //第一个[]可以不写大小,第二个必须写,因为表示类型
void fun2( int (*p) [5] )
int main()
int arr[2][5]=1,2,3,4,5,6,7,8,9,0;
fun1(arr);
fun2(arr);
return 0;
虽然上面的代码什么都没有做,但是它在编译,链接执行的时候都没有错。也就是说二维数组传参时,传给函数的是一个数组指针,同时函数的形参类型也必须是一个数组指针类型。
本文出自 “牛丽” 博客,请务必保留此出处http://15129279495.blog.51cto.com/10845420/1737674
以上是关于C 指针&&数组的主要内容,如果未能解决你的问题,请参考以下文章