c中指针指针、指针的指针、指针数组和数组指针
“天目崖”通过精心收集,向本站投稿了5篇c中指针指针、指针的指针、指针数组和数组指针,下面小编给大家整理后的c中指针指针、指针的指针、指针数组和数组指针,欢迎阅读!
篇1:十六、数组和指针
指针和数组有着密切的关系,任何能由数组下标完成的操作也都可用指针来实现,但程序中使用指针可使代码更紧凑、更灵活,
一、指向数组元素的指针
我们定义一个整型数组和一个指向整型的指针变量:
int a[10], *p;
和前面介绍过的方法相同,可以使整型指针p指向数组中任何一个元素,假定给出赋值运算
p=&a[0];
此时,p指向数组中的第0号元素,即a[0],指针变量p中包含了数组元素a[0]的地址,由于数组元素在内存中是连续存放的,因此,我们就可以通过指针变量p及其有关运算间接访问数组中的任何一个元素。
Turbo C中,数组名是数组的第0号元素的地址,因此下面两个语句是等价的
p=&a[0];
p=a;
根据地址运算规则,a+1为a[1]的地址,a+i就为a[i]的地址。
下面我们用指针给出数组元素的地址和内容的几种表示形式:
(1). p+i和a+i均表示a[i]的地址, 或者讲,它们均指向数组第i号元素, 即指向a[i]。
(2). *(p+i)和*(a+i)都表示p+i和a+i所指对象的内容,即为a[i]。
(3). 指向数组元素的指针, 也可以表示成数组的形式,也就是说,它允许指针变量带下标, 如p[i]与*(p+i)等价。
假若: p=a+5;
则p[2]就相当于*(p+2), 由于p指向a[5], 所以p[2]就相当于a[7]。而p[-3]就相当于*(p-3), 它表示a[2]。
二、指向二维数组的指针
1.二维数组元素的地址
为了说明问题, 我们定义以下二维数组:
int a[3][4]={{0,1,2,3}, {4,5,6,7}, {8,9,10,11}};
a为二维数组名,此数组有3行4列, 共12个元素。但也可这样来理解,数组a由三个元素组成:a[0],a[1],a[2]。而每个元素又是一个一维数组, 且都含有4个元素(相当于4列),例如,a[0]所代表的一维数组所包含的 4 个元素为a[0][0], a[0][1], a[0][2], a[0][3]。如图所示:
______ _______________
a---| a[0] | ____ | 0 | 1 | 2 | 3 |
|______| |___|___|___|___|
| a[1] | ____ | 4 | 5 | 6 | 7 |
|______| |___|___|___|___|
| a[2] | ____ | 8 | 9 | 10| 11|
|______| |___|___|___|___|
但从二维数组的角度来看,a代表二维数组的首地址,当然也可看成是二维数组第0行的首地址。a+1就代表第1行的首地址,a+2就代表第2行的首地址。如果此二维数组的首地址为1000,由于第0行有4个整型元素,所以a+1为1008,a+2也就为1016。如图所示
_______________
(1000) ____ | 0 | 1 | 2 | 3 |
|___|___|___|___|
(1008) ____ | 4 | 5 | 6 | 7 |
|___|___|___|___|
(1016) ____ | 8 | 9 | 10| 11|
|___|___|___|___|
既然我们把a[0],a[1],a[2]看成是一维数组名,可以认为它们分别代表它们所对应的数组的首地址,也就是讲,a[0]代表第 0 行中第 0 列元素的地址,即&a[0][0], a[1]是第1行中第0列元素的地址,即&a[1][0],根据地址运算规则,a[0]+1即代表第0行第1列元素的地址,即&a[0][1],一般而言,a[i]+j即代表第i行第j列元素的地址, 即&a[i][j],
另外,在二维数组中,我们还可用指针的形式来表示各元素的地址。如前所述,a[0]与*(a+0)等价,a[1]与*(a+1)等价,因此a[i]+j就与*(a+i)+j等价,它表示数组元素a[i][j]的地址。
因此,二维数组元素a[i][j]可表示成*(a[i]+j)或*(*(a+i)+j),它们都与a[i][j]等价,或者还可写成(*(a+i))[j]。
另外, 要补充说明一下, 果你编写一个程序输出打印a和*a,你可发现它们的值是相同的,这是为什么呢? 我们可这样来理解:
首先,为了说明问题,我们把二维数组人为地看成由三个数组元素a[0],a[1],a[2]组成,将a[0],a[1],a[2]看成是数组名它们又分别是由4个元素组成的一维数组。因此,a表示数组第0行的地址, 而*a即为a[0], 它是数组名, 当然还是地址,它就是数组第0 行第0 列元素的地址。
2.指向一个由n个元素所组成的数组指针
在Turbo C中, 可定义如下的指针变量:
int (*p)[3];
指针p为指向一个由3个元素所组成的整型数组指针。在定义中,圆括号是不能少的, 否则它是指针数组, 这将在后面介绍。这种数组的指针不同于前面介绍的整型指针,当整型指针指向一个整型数组的元素时,进行指针(地址)加1运算,表示指向数组的下一个元素,此时地址值增加了2(因为放大因子为2),而如上所定义的指向一个由3个元素组成的数组指针,进行地址加1运算时,其地址值增加了6(放大因子为2x3=6),
这种数组指针在Turbo C中用得较少,但在处理二维数组时, 还是很方便的。例如:
int a[3][4], (*p)[4];
p=a;
开始时p指向二维数组第0行,当进行p+1运算时,根据地址运算规则,此时放大因子为4x2=8,所以此时正好指向二维数组的第1行。和二维数组元素地址计算的规则一样,*p+1指向a[0][1],*(p+i)+j则指向数组元素a[i][j]。
例:
int a[3][4]={
{1,3,5,7},
{9,11,13,15},
{17,19,21,23}
};
main
{
int i,(*b)[4];
b=a+1; /* b指向二维数组的第1行, 此时*b[0]是a[1][0] */
for(i=1;i<=4;b=b[0]+2,i++) /* 修改b的指向, 每次增加2 */
printf(%d\t,*b[0]);
printf(\n);
for(i=0; i<3; i++)
{
b=a+i; /* 修改b的指向,每次跳过二维数组的一行 */
printf(%d\t,*(b[i]+1));
}
printf (\n);
}
程序运行结果如下:
9 13 17 21
3 11 19
三、字符指针
我们已经知道,字符串常量是由双引号括起来的字符序列,例如:
a string
就是一个字符串常量,该字符串中因为字符a后面还有一个空格字符,所以它由8个字符序列组成。在程序中如出现字符串常量C编译程序就给字符串常量按排一存贮区域,这个区域是静态的,在整个程序运行的过程中始终占用,平时所讲的字符串常量的长度是指该字符串的字符个数, 但在按排存贮区域时, C 编译程序还自动给该字符串序列的末尾加上一个空字符'\0',用来标志字符串的结束,因此一个字符串常量所占的存贮区域的字节数总比它的字符个数多一个字节。
Turbo C中操作一个字符串常量的方法有:
篇2:c中指针指针、指针的指针、指针数组和数组指针
一、指针
如果在程序中定义一个变量,在对程序进行编译,系统会自动给这个变量分配内存单元,根据不同的类型,分配不同长度的空间,如int占用4个字节,char占用1个字节,内存单元中每个字节都有编号,这就是地址。由于可通过地址能够找到所需的变量单元,可以说地址指向该变量单元。打个比方,一个房间的门口挂了一个房间号301,这个301就是房间的地址,将该地址形象化为指针。对于一个内存单元来说,单元的地址(编号)即为指针,其中存放的数据才是该单元的内容。
严格地说,一个指针是一个地址,是一个常量,
而一个指针变量却可以被赋予不同的指针值,是变量。但常把指针变量简称为指针。为了避免混淆,约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问内存单元。
例如:
int a=12;
int *p=&a;
二、指针的指针(二级指针)
简单来说,二级指针变量就是一级指针变量的地址。
例如:
int a=12;
int *p=&a;
int **=&p;
篇3:数组和指针再次来袭
1,数组和指针的定义于声明:
定义:只能出现一次,用来确定对象的类型和大小,并为其分配空间,
声明:可以出现多次,描述对象的类型,用于指定其他地方定义的对象,不为对象分配空间。
所以说extern char a[]与extern char a[10]等价,因为这是声明,不分配空间。
看一个关于数组指针的例子:
例1:
#include 如果将&a强制类型转换为(char (*)[4])&a后就可以赋值给char (*p)[4]了,p4+1相当于加了4个字节,而不是5,因为p4的大小为4。 例2: #include 结果分析:p的地址为1ef7f4,p里面存放的是结构体的地址,所以p+0x1就要加一个结构体的大小20,转换为16进制,结果就是1ef808, 将p转化为无符号长整型,加1就是直接加十进制1,结果就是1ef7f5。将p转换为整型指针,占四个字节,加1就相当于加1*sizeof(int *),结果就是1ef7f8。 例3:vs中小端存储: int main(){ int a[4] = { 1, 2, 3, 4 }; int *ptr1 = (int *)(&a + 1); int *ptr2 = (int *)((int)a + 1); printf(“%x,%x”, ptr1[-1], *ptr2); system(“pause”); return 0;} 经常遇到这两个概念,很容易混淆,这里细细总结一下, 指针数组:是一个数组,数组的元素是指针。数组占多少个字节由数组本身决定。 数组指针:是一个指针,它指向一个数组。在32位系统下永远是占4 个字节。 举例说明: 1)int *p1[n]; 2)int (*p2)[n]; 1)“[]”的优先级比“*”要高。p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素, 即p1是指针数组,其包含n个指向int 类型数据的指针。 2)“”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。即p2是数组指针,它指向一个包含n 个int 类型数据的数组。 如要将二维数组赋给一指针,应这样赋值: int a[3][4]; int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。 p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0] p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][] 所以数组指针也称指向一维数组的指针,亦称行指针。 一、数组的指针、指针数组以及指向指针的指针 考虑数组的指针的时候我们要同时考虑类型和维数这两个属性,换一句话,就是说一个数组排除在其中存储的数值,那么可以用类型和维数来位置表示他的种类。 A)一维数组 在c和c++中数组的指针就是数组的起始地址(也就第一个元素的地址),而且标准文档规定数组名代表数组的地址(这是地址数值层面的数组表示)。例如: p=&a[0]//和p=a是等价的: 因为a是数组名,所以他是该数组的地址,同时因为第一个元素为a[0],那么&a[0]也代表了该数组的地址。但是我们是不是就说一个数组名和该数组的第一个元素的&运算是一回事呢?在一维的时候当时是的,但是在高维的时候,我们要考虑到维数给数组带来的影响。 a[10]是一个数组,a是数组名,它是一个包含10个int类型的数组类型,不是一般的指针变量噢!(虽然标准文档规定在c++中从int[]到int*直接转换是可以的,在使用的时候似乎在函数的参数为指针的时候,我们将该数组名赋值没有任何异样),a代表数组的首地址,在数字层面和a[10]的地址一样。这样我们就可以使用指针变量以及a来操作这个数组了。 所以我们要注意以下问题: (1) p[i]和a[i]都是代表该数组的第i+1个元素; (2) p+i和a+i代表了第i+1个元素的地址,所以我们也可以使用 *(p+I)和*(a+I)来引用对象元素; (3)p+1不是对于指针数量上加一,而是表示从当前的位置跳过当前指针指向类型长度的空间,对于win32的int为4byte; B)多维数组 对于二维数组a[4][6];由于数组名代表数组的起始地址,所以a(第一层)和第一个元素a[0][0]地址的数字是相同的,但是意义却是不同的。对于该数组我们可以理解为:a的一维数组(第一层),它有四个元素a[0]、a[1]、a[2]、a[3](第二层),而每个元素又含有6个元素a[0][0],a[0][1],a[0][2],a[0][3],a[0][4],a[0][5](第三层),…到此我们终于访问到了每个元素了,这个过程我们经历了:a->a[0]->a[0][0]; 整体来讲:a是一个4行5列的二维数组,a表示它指向的数组的首地址(第一个元素地址&a[0]),同时a[0]指向一行,它是这个行的名字(和该行的第一个元素的首地址相同(第一个元素为地址&a[0][0]))。所以从数字角度说:a、a[0]、&a[0][0]是相同的,但是他们所处的层次是不同的。 既然a代表二维数组,那么a+i就表示它的第i+1个元素*(a+i)的地址,而在二维数组中 *(a+i)又指向一个数组,*(a+i)+j表示这个数组的第j+1个元素的地址,所以要访问这个元素可以使用 *(*(a+i)+j)(也就是a[i][j])。 他们的示意图为(虚线代表不是实际存在的): 对照这个图,如下的一些说法都是正确的(对于a[4][6]): a是一个数组类型,*a指向一个数组; a+i指向一个数组; a、*a和&a[0][0]数值相同; a[i]+j和*(a+i)+j是同一个概念; 总结一下就是:我们对于二维指针a,他指向数组a[0,1,2,3],使用*,可以使他降级到第二层次,这样*a就指向了第一个真正的数组。对于其他的情况我们也可以采用相同的方式,对于其他维数和类型的数组我们可以采用相类似的思想, 说到指向数组的指针,我们还可以声明一个指针变量让它指向一个数组。例如: 这时p就是一个指针,要指向一个含有5个int类型元素的数组,指向其他的就会出现问题。 这个时候我们可以使用上面的什么东西来初始化呢? 我们可以使用*a,*(a+1),a[2]等。 原因很简单:我们在一个二维的数组中,那么表达方式有上面的相互类似的意义呢?只有 *a,*(a+1),a[2]等, C)指针数组 一个指针数组是指一个数组中的每个元素都是一个指针,例如: 或者 此时p是一个指针(数值上和&p[0]一样); 在前面有int t[10]; 那么这里我们用什么指向int *t[10]中的t呢?我们要使用一个指针的指针: 这是因为:在int *t[10]中,每个元素是指针,那么同时t又指向这个数组,数组上和&t[0]相同,也就是指向t[0],指向一个指针变量,可以说是一个指针的指针了,所以自然要用 D)指针的指针 一个指针变量内部可以存储一个值,这个值是另外一个对象的地址,所以我们说一个指针变量可以指向一个普通变量,同样这个指针变量也有一个地址,也就是说有一个东西可以指向这个指针变量,然后再通过这个指针变量指向这个对象。那么如何来指向这个指针变量呢?由于指针变量本身已经是一个指针了(右值),那么我们这里就不能用一般的指针了,需要在指针上体现出来这些特点,我们需要定义指针的指针(二重指针)。 综合以上的所有点,下面是我们常常看到一些匹配(也是经常出错的地方): 函数 不会产生编译时刻的可能值(但逻辑上不一定都对) 函数 不会产生编译时刻的可能值(但逻辑上不一定都对) fun1 a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i] fun2 b,b+i, fun3 d fun4 a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i] fun5 a, &a[i], *b ,b[i],&b[i][j] ,&c ,d[i] fun6 b 【c中指针指针、指针的指针、指针数组和数组指针】相关文章: 5.C语言指针笔试题篇4:再谈指针数组与数组指针
篇5:c语言指针
int a[10]; int *p;
int (*p)[5];
int *p[10];//而不能是int (*p)[10]
char *p[10];
int * pt=t;//使用pt指向t
int **pt=t;
int **pt;
int *p1=&i; int**p2=&p1;
int a[3],b[2][3],c,*d[3]; void fun1(int *p); void fun2(int (*p)[3]); void fun3(int **p); void fun4(int p[3]); void fun5(int p[]); void fun6(int p[2][3]); void fun7(int (&p)[3]);






文档为doc格式