当前位置:文档之家› 第11章 指针与数组--第一讲

第11章 指针与数组--第一讲

二维数组和指针

要用指针处理二维数组,首先要解决从存储的角度对二维数组的认识问题。我们知道,一个二维数组在计算机中存储时,是按照先行后列的顺序依次存储的,当把每一行看作一个整体,即视为一个大的数组元素时,这个存储的二维数组也就变成了一个一维数组了。而每个大数组元素对应二维数组的一行,我们就称之为行数组元素,显然每个行数组元素都是一个一维数组 下面我们讨论指针和二维数组元素的对应关系,清楚了二者之间的关系,就能用指针处理二维数组了。 设p是指向数组a的指针变量,若有: p=a[0]; 则p+j将指向a[0]数组中的元素a[0][j]。 由于a[0]、a[1]┅a[M-1]等各个行数组依次连续存储,则对于a数组中的任一元素a[i][j],指针的一般形式如下: p+i*N+j 元素a[i][j]相应的指针表示为: *( p+i*N+j) 同样,a[i][j]也可使用指针下标法表示,如下: p[i*N+j] 例如,有如下定义: int a[3][4]={{10,20,30,40,},{50,60,70,80},{90,91,92,93}}; 则数组a有3个元素,分别为a[0]、a[1]、a[2]。而每个元素都是一个一维数组,各包含4个元素,如a[1]的4个元素是a[1][0]、a[1][1]、a[1]2]、a[1][3]。 若有: int *p=a[0]; 则数组a的元素a[1][2]对应的指针为:p+1*4+2 元素a[1][2]也就可以表示为:*( p+1*4+2) 用下标表示法,a[1][2]表示为:p[1*4+2] 特别说明: 对上述二维数组a,虽然a[0]、a都是数组首地址,但二者指向的对象不同,a[0]是一维数组的名字,它指向的是a[0]数组的首元素,对其进行“*”运算,得到的是一个数组元素值,即a[0]数组首元素值,*a等价于a[0] a[0]等价于&a[0][0],因此,*a[0]与a[0][0]是同一个值;

关于二维数组地址和指针之间的赋值

在开发工业以太网项目的时候经常遇到一些小细节问题,在建立数据报进行传输的过程中传递txbuf缓冲区的地址的时候就遇到类似下面的问题。 一.简单说明1 定义一个2X3的int型的二维数组int array[2][3];并且给这个二维数组赋值1,2,3,4,5,6;array[0][0]=1 array[0][1]=2 array[0][2]=3 array[1][0]=4 array[1][1]=5 array[1][2]=6 输出结果 1 2 3 4 5 6 array[0]表示第一行的首地址,也就是第一行第一个数的地址,也就是&array[0][0] So array[0]==&array[0][0];其实&array[0]还==array[0]==&array[0][0],都表示第一行的首地址。 array[1]是第二行的首地址,也就是第二行第一个数的地址,也就是&array[1][0] so array[1]=&array[1][0];试试&array[1]还==array[1]==&array[1][0] 定义一个指针变量int *p;将第一行的首地址赋给p有3种方式。 1. p=array[0]; 2. p=&array[0]; 3. p=&array[0][0]; p[0]就等同于array[0][0],也就是p[0]==1;(为了形象记忆,可以用替换的角度去记忆和理解。因为之前说过p=array[0], so, p[0]就把p换成array[0]再加上[0]就是arary[0][0]) p[1]等于array[0][1]等于2 p[2]等于array[0][2]等于3

指向二维数组的指针

指向二维数组的指针 一. 二维数组元素的地址 为了说明问题, 我们定义以下二维数组: 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]。如图5.所示: ┏━━━━┓┏━┳━┳━┳━┓ a─→┃a[0] ┃─→┃0 ┃1 ┃2 ┃3 ┃ ┣━━━━┫┣━╋━╋━╋━┫ ┃a[1] ┃─→┃4 ┃5 ┃6 ┃7 ┃ ┣━━━━┫┣━╋━╋━╋━┫ ┃a[2] ┃─→┃8 ┃9 ┃10┃11┃ ┗━━━━┛┗━┻━┻━┻━┛ 图5. 但从二维数组的角度来看, a代表二维数组的首地址, 当然也可看成是二维数组第0行的首地址。a+1就代表第1行的首地址, a+2就代表第2行的首地址。如果此二维数组的首地址为1000, 由于第0行有4个整型元素, 所以a+1为1008, a+2 也就为1016。如图6.所示 a[3][4] a ┏━┳━┳━┳━┓ (1000)─→┃0 ┃1 ┃2 ┃3 ┃ a+1 ┣━╋━╋━╋━┫ (1008)─→┃4 ┃5 ┃6 ┃7 ┃ a+2 ┣━╋━╋━╋━┫ (1016)─→┃8 ┃9 ┃10┃11┃ ┗━┻━┻━┻━┛ 图6. 既然我们把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 列元素的地址。

关于二维数组和指向指针的指针

以前一直有种误解: 二维数组的是数组的数组,所以数组的首地址是指向第一个元素指针,而这个元素又是一个数组,所以把数组首地址理解为指向指针的指针。 如int a[3][2];,以前一直认为a是一个指向int指针的指针,即是一个int**。最近发现这是错的。 如果int **p=a; 编译就会报错。如果强制转换int **p=(int **)a,则使用p[i][j]访问数组元素时出错。 首先,因为a的定义为int a[3][2];则a的类型是int* [3][2]数组类型,或者int* [][2],即指向大小为2的数组的指针,类型与int **不同,所以int **p=a;出错。 其次,考虑p[i][j]访问a的数组元素时出错的问题。当我们使用指向二维数组的指针的下标运算来访问数组元素时,如a[i][j],它等同于*(a+i*2+j);即必须要知道第二维的大小才能访问。考虑我使用p[i][j]的后果:p是int**,所以p[i]为*(p+i),而这个结果被视作一个指针,在这里记做pp=*(p+i),所以p[i][j]等同于pp[j]。最终的结果为*(pp+j),并将这个结果解释为一个int值。 int a[3][2]; int val=0; for(int i=0;i<3;++i) { for(int j=0;j<2;++j) { a[i][j]=val++; } } /*使用a[i][j]的方式显然可以正常访问该二维数组*/ /*下面使用指针直接访问,当然是不是int**了……*/ int *p=&a[0][0];/*注意,此处使用int *p=a;或者int *p=a[0];是不对的,p的类型是int型指针,*a或者a[0]是int (*)[2]类型,编译会报错的,* *尽管&a[0][0]、a、a[0]的数值相同……*/ for(int i=0;i<6;++i) { p[i];/*这样可以遍历所有元素*/ }

计算机二级c语言第九章 数组和指针习题与答案

第九章数组和指针 1、有以下程序 main() { int a[]={2,4,6,8,10}, y=0, x, *p; p=&a[1]; for(x= 1; x< 3; x++) y += p[x]; printf("%d\n",y); } 程序运行后的输出结果是 A)10 B)11 C)14 D)15 2、有以下程序 void sum(int a[]) { a[0] = a[-1]+a[1]; } main() { int a[10]={1,2,3,4,5,6,7,8,9,10}; sum(&a[2]); printf("%d\n", a[2]); } 程序运行后的输出结果是 A)6 B)7 C)5 D)8 3、有以下程序 main() { int p[8]={11,12,13,14,15,16,17,18},i=0,j=0; while(i++< 7) if(p[i]%2) j+=p[i]; printf("%d\n",j); } 程序运行后的输出结果是 A)42 B)45 C)56 D)60 4、设有定义语句 int x[6]={2,4,6,8,5,7},*p=x,i; 要求依次输出x数组6个元素中的值,不能完成此操作的语句是 A)for(i=0;i<6;i++) printf("%2d",*(p++)); B)for(i=0;i<6;i++) printf("%2d",*(p+i)); C)for(i=0;i<6;i++) printf("%2d",*p++); D)for(i=0;i<6;i++) printf("%2d",(*p)++); 5、有以下程序 #include < stdio.h > main() { int a[]={1,2,3,4,5,6,7,8,9,10,11,12,},*p=a+5,*q=NULL; *q=*(p+5); printf("%d %d\n",*p,*q); } 程序运行后的输出结果是 A)运行后报错 B)6 6 C)6 11 D)5 10

第4章 指针思考与练习题答案

第4章指针 思考与练习题 1、什么叫内存单元的地址?什么叫指针? 答:在计算机内部的存储器(简称内存)中,每一个字节单元,都有一个编号,称为地址。内存单元的编号,称为内存单元的地址。 在C++语言中,内存单元的地址称为指针。 2、什么叫指针变量?什么叫指针的目标? 答:专门用来存放地址的变量,称为指针变量(pointer variable)。指针指向的内存区域中的数据称为指针的目标。 3、什么叫空指针?其作用是什么? 答:所谓空指针就是指针变量的内容为零的状态。 4、指针运算的实质是什么? 答:指针运算是以指针变量所存放的地址量作为运算量而进行的运算。因此,指针运算的实质就是地址的计算。 5、指针有哪些运算?请枚举这些计算。 答:指针运算的种类是有限的,它只能进行算术运算、关系运算和赋值运算。 6、什么叫数组的指针?什么叫指针数组的指针? 答:在C++语言中,数组的指针是指数组在内存中的起始地址。 指针变量数组和普通的一般变量数组一样,编译系统在处理指针数组说明时,按照指定的存储类型为它在内存中分配一定的连续存储空间,这时指针数组名就表示该指针数组的存储首地址,即指针数组的指针。 7、什么叫二级指针变量?什么叫多级指针变量? 答:对于指向处理数据的指针变量称为一级指针变量,简称一级指针。而把指向一级指针变量的指针变量称为二级指针变量,简称二级指针。我们把一个指向指针变量的指针变量,称为多级指针变量。 8、new运算符的作用是什么?delete运算符的作用是什么? 答:运算符new主要用于分配内存,并获得分配到的内存的首地址,通常需要将其赋给相应数据类型的指针。如果程序中不再需要由new分配的内存空间时,用运算符delete

二次指针与二维数组

二次指针与二维数组 首先我们需要知道,什么是二次指针?下面的代码就定义了一个二次指针变量p2。 char **p2; 还是通过图来说明变量、指针变量、二次指针变量的关系吧。 对于代码: char c = …h?; char *p1 = &c; char **p2 = &p1; 其中c、p1、p2的关系如下图所示: 由于“指针生成”规则(参见教材P176)的存在,我们无法将一个数组传递给一个函数。一个折中的解决办法是传递这个数组的第一个元素的地址,以及数组的各个维数,然后在函数中计算得到要操作的数组元素的地址来操作该数组元素。例如: void fun(char *p, int n, int m)//从传入指针指向元素开始,将m*n个元素赋值为5 { for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) *(p + i*n + j) = 5; } main() { char a[2][3]; fun(&a[0][0], 2, 3); return 0; } 显然,其中的fun(&a[0][0], 2, 3);对数组的操作相当于: for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) a[i][j] = 5; 在这段代码中,a[i][j]的形式显然更为浅显易懂,也*(p + i*n + j) = 5更为安全(不容易写错)。接下来我们要做的,就是希望实现这样的功能:函数能够以a[i][j]这样的下标处理一个维度变化的二维数组。 通过指针数组,我们可以实现一个一维长度不同的二维数组。当然,这也就意味着该二维数

指针和数组习题

一、1 数组可以在定义时整体赋初值,但不能在赋值语句中整体赋值。() 2. 取数组a的第5个元素的地址,正确的写法是() A) *a[4] B) &a[4]C) a[4] D) *(a+4) 3. 程序段输出结果是() int main() { double number = 12345.12345678; cout << setw(10) << setprecision(5) << number << endl; cout << setw(10) << setprecision(10) << number << endl; return 0; } 12345 B)12345 C) 12345 D) 12345 12345.12346 12345.12345 12345.12345 12345.1235 4、若x为整形变量,p是基类型为整形的指针变量,则正确的赋值表达式() A p=&x B p=x C *p=&x D *p=*x 5,设p1和p2均为指向同一个int型一维数组的指针变量,k为int型变量,下列不正确的语句是() A k=*p1+*p2 B k=*p1*(*p2) C p2=k D p1=p2 6.对于相同类型的指针变量,不能进行()运算。 A,+ B,- C,= D,== 7.有函数定义如下,则其返回值为() int *f(int a) { Int*p,n; n=a; p=&n; return p; } A 一个不可用的存储单元地址值 B一个不可用的存储单元地址值 C n中的值 D 形参a中得值 8,下列关于字符串的描述中,错误的是() A,一维字符数组可以存放一个字符串 B,可以用一个字符串给二维字符数组赋值 C,二维字符数组可以存放多个字符串 D;可以用一个字符串给二维字符数组进行初始化 9;下列关于字符数组的描述中,错误的是() A.字符数组中得每一个元素都是字符 B,字符数组可以使用初始值表进行初始化 C,字符数组可以存放字符串 D 字符数组就是字符串 10;下列关于数组下标的描述中,错误的是() A;C++中,数组元素的下标是从0开始的 B,数组元素下标是一个整型常量表达式

二重指针详解

二重指针详解 朱有鹏 1.二重指针 1.1、二重指针与普通一重指针的区别 本质上来说,二重指针和一重指针的本质都是指针变量,指针变量的本质就是变量。 一重指针变量和二重指针变量本身都占4字节内存空间, 1.2、二重指针的本质 (1)二重指针本质上也是指针变量,和普通指针的差别就是它指向的变量类型必须是个一重指针。二重指针其实也是一种数据类型,编译器在编译时会根据二重指针的数据类型来做静态类型检查,一旦发现运算时数据类型不匹配编译器就会报错。 (2)C语言中如果没有二重指针行不行?其实是可以的。一重指针完全可以做二重指针做的事情,之所以要发明二重指针(函数指针、数组指针),就是为了让编译器了解这个指针被定义时定义它的程序员希望这个指针被用来指向什么东西(定义指针时用数据类型来标记,譬如int*p,就表示p要指向int型数据),编译器知道指针类型之后可以帮我们做静态类型检查。编译器的这种静态类型检查可以辅助程序员发现一些隐含性的编程错误,这是C 语言给程序员提供的一种编译时的查错机制。 (3)为什么C语言需要发明二重指针?原因和发明函数指针、数组指针、结构体指针等一样的。 1.3、二重指针的用法 (1)二重指针指向一重指针的地址 (2)二重指针指向指针数组的 (3)实践编程中二重指针用的比较少,大部分时候就是和指针数组结合起来用的。 (4)实践编程中有时在函数传参时为了通过函数内部改变外部的一个指针变量,会传这个指针变量的地址(也就是二重指针)进去 1.4、二重指针与数组指针 (1)二重指针、数组指针、结构体指针、一重指针、普通变量的本质都是相同的,都是变量。 (2)所有的指针变量本质都是相同的,都是4个字节,都是用来指向别的东西的,不同类型的指针变量只是可以指向的(编译器允许你指向的)变量类型不同。 (3)二重指针就是:指针数组指针 2、二维数组 2.1、二维数组的内存映像 一维数组在内存中是连续分布的多个内存单元组成的,而二维数组在内存中也是连续分布的多个内存单元组成的。从内存角度来看,一维数组和二维数组没有本质差别。如:二维数组int a[2][5]和一维数组int b[10]对应关系如下: a[0][0]a[0][1]a[0][4]a[1][0]a[1][1]a[1][4] b[0]b[1]b[4]b[5]b[6]b[9] 既然二维数组都可以用一维数组来表示,那二维数组存在的意义和价值在哪里?明确告诉大家:二维数组a和一维数组b在内存使用效率、访问效率上是几乎相同。使用用二维数组而不用一维数组,原因是在某些情况下,二维数组更好理解、利于组织。我们使用二维数组,并不是必须,而是一种简化编程的方式。一维数组的出现其实也不是必然的,也是为了

C语言多维数组与多级指针

C语言多维数组与多级指针 多维数组与多级指针也是初学者感觉迷糊的一个地方。超过二维的数组和超过二级的指针其实并不多用。如果能弄明白二维数组与二级指针,那二维以上的也不是什么问题了。所以本节重点讨论二维数组与二级指针。 一、二维数组 1、假想中的二维数组布局 我们前面讨论过,数组里面可以存任何数据,除了函数。下面就详细讨论讨论数组里面存数组的情况。Excel 表,我相信大家都见过。我们平时就可以把二维数组假想成一个excel表,比如: char a[3][4]; 2、内存与尺子的对比 实际上内存不是表状的,而是线性的。见过尺子吧?尺子和我们的内存非常相似。一般尺子上最小刻度为毫米,而内存的最小单位为1 个byte。平时我们说32 毫米,是指以零开始偏移32 毫米;平时我们说内存地址为0x0000FF00 也是指从内存零地址开始偏移0x0000FF00 个byte。既然内存是线性的,那二维数组在内存里面肯定也是线性存储的。实际上其内存布局如下图:

以数组下标的方式来访问其中的某个元素:a[i][j]。编译器总是将二维数组看成是一个一维数组,而一维数组的每一个元素又都是一个数组。a[3]这个一维数组的三个元素分别为: a[0],a[1],a[2]。每个元素的大小为sizeof(a[0]),即sizof(char)*4。由此可以计算出a[0],a[1],a[2]三个元素的首地址分别为& a[0],& a[0]+ 1*sizof(char)*4,& a[0]+ 2*sizof(char)*4。亦即a[i]的首地址为& a[0]+ i*sizof(char)*4。这时候再考虑a[i]里面的内容。就本例而言,a[i]内有4个char 类型的元素,其每个元素的首地址分别为&a[i],&a[i]+1*sizof(char),&a[i]+2*sizof(char)&a[i]+3*sizof(char),即a[i][j]的首地址为 &a[i]+j*sizof(char)。再把&a[i]的值用a 表示,得到a[i][j]元素的首地址为:a+ i*sizof(char)*4+ j*sizof(char)。同样,可以换算成以指针的形式表示:*(*(a+i)+j)。 经过上面的讲解,相信你已经掌握了二维数组在内存里面的布局了。下面就看一个题: #include intmain(int argc,char * argv[]) { int a [3][2]={(0,1),(2,3),(4,5)}; int *p; p=a [0]; printf("%d",p[0]); } 问打印出来的结果是多少? 很多人都觉得这太简单了,很快就能把答案告诉我:0。不过很可惜,错了。答案应该是1。如果你也认为是0,那你实在应该好好看看这个题。花括号里面嵌套的是小括号,而不是花括号!这里是花括号里面嵌套了逗号表达式!其实这个赋值就相当于 int a [3][2]={ 1, 3,5}; 所以,在初始化二维数组的时候一定要注意,别不小心把应该用的花括号写成小括号

C语言 数组和指针练习题

若当堂没做完,下周四之前上交也可。 至ftp://211.64.82.253/ 用户名和密码:stu C语言程序设计练习题——数组 一、选择题 77、以下对一维数组a的正确说明是_d ___ A、char a(10); B、int a[ ]; C、int k=5,a[k]; D、char a[ ]={'a' , 'b' , 'c'}; 78、若有说明语句:int a[2][4];,则对a数组元素的正确引用是_a___ A、a[0][3] B、a[0][4] C、a[2][2] D、a[2][2+1] 79、以下能对二维数组y进行初始化的语句是_b__ A、static int y[2][ ]={{1,0,1}, {5,2,3}}; B、static int y[ ][3]={{1,2,3}, {4,5,6}}; C、static int y[2][4]={{1,2,3}, {4,5} , {6}}; D、static int y[ ][3]={{1,0,1,0}, { }, {1,1}}; 80、若有说明语句:int y[ ][4]={0,0};则下面叙述不正确的是_d___ A、数组y的每个元素都可得初值0 B、二维数组y的行数为1 C、该说明等价于int y[ ][4]={0}; D、只有元素y[0][0]和y[0][1]可得到初值0,其余元素均得不到初值0 81、以下各组选项中,均能正确定义二维实型数组s的选项是_c___ A、float s[3][4]; B、float s(3,4); float s[ ][4]; float s[ ][ ]={{0};{0}}; float s[3][ ]={{1},{0}}; float s[3][4]; C、 float s[3][4]; D、float s[3][4]; static float s[ ][4]={{0},{0}}; float s[3][ ]; auto float s[ ][4]={{0},{0},{0}}; float s[ ][4]; 82、若有说明语句:int a[ ][3]={1,2,3,4,5,6,7,8}; ,则a数组的行数为__a__ A、3 B、2 C、无确定值 D、1 83、若二维数组y有m列,则在y[i][j]前的元素个数为_B___ A、j*m+i B、i*m+j C、i*m+j-1 D、i*m+j+1 84、下面程序中有错误的行是__D__ 1、 main( ) 2、 { 3、 int x[3]={1}; 4、 int k; 5、 scanf("%d", &x); 6、 for (k=1; k<3; k++) 7、 x[0]=x[0]+x[i]; 8、 printf("x[0]=%d\n", x[0]); 9、 } A、3 B、6 C、7 D、5 85、若有以下语句,则正确的描述是__b__ char x[ ]="12345"; char y[ ]={'1', '2', '3', '4', '5'}; A、x数组与y数组的长度相同 B、x数组长度大于y数组长度 C、x数组长度小于y数组长度

指针数组和数组指针的区别

指针数组和数组指针的区别 以前这两问题一直都不是很清晰,写程序也管不了这么多,只要不出错能跑出结果就行,其实很多用C的程序员对C的基础知识都一知半解。 这次要给学生讲指针这一章,特意关注了一下。 而网上一些相关回答也没严格区分,显得十分晦涩。 这里整理如下: 数组指针(也称行指针) 定义int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。 如要将二维数组赋给一指针,应这样赋值: 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][] 所以数组指针也称指向一维数组的指针,亦称行指针。 指针数组 定义int *p[n]; []优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样*p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。 如要将二维数组赋给一指针数组: int *p[3]; int a[3][4]; for(i=0;i<3;i++) p[i]=a[i]; 这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]

指向多维数组的指针变量

指向多维数组的指针变量 1 多维数组的指针 多维数组可以看作是一维数组的延伸,多维数组的内存单元也是连续的内存单元。换句话说,C语言实际上是把多维数组当成一维数组来处理的。下面以二维数组为例说明这个概念。 比如,现在有一个int型的二维数组a[3][4],计算机认为这是一个一维的数组a[3],数组的三个元素分别是a[0],a[1]和a[2]。其中每个元素又是一个一维数组,例如a[0]又是一个包含a[0][0],a[0][1],a[0][2]和a[0][3]共4个元素的数组。如果我们要引用数组元素a[1][2],可以首先根据下标1找到a[1],然后在a[1]中找到第3个元素a[1][2]。假设数组a的起始地址为FF10,对应的内存情况如图: DS:FF10 a[0][0] DS:FF12 a[0][1] DS:FF14 a[0][2] DS:FF16 a[0][3] DS:FF18 a[1][0] DS:FF1A a[1][1] DS:FF1C a[1][2] DS:FF1E a[1][3] DS:FF20 a[2][0] DS:FF22 a[2][1] DS:FF24 a[2][2] DS:FF26 a[2][3] 可以看到,二维数组a[3][4]的12个元素在内存中是顺序排列的,因此&a[0][0]是数组第一个元素的地址,为FF10。 a[0][0],a[0][1]这些数组元素都有具体的内存单元值。但是,a[0],a[1]和a[2]这三个数组元素不占用内存单元,它们只是代号(其实就是一个指针常量),是虚拟的东西。a[0]本身又是一个数组,包含a[0][0],a[0][1],a[0][2]和a[0][3],那么a[0]作为数组名称,按照C语言的语法,a[0]就是数组首地址,也就是数组第一个元素的地址,即a[0][0]的地址FF10。同理,a[1]是第一个元素a[1][0]的地址,即FF18;a[2]是第一个元素a[2][0]的地址,即FF20。 相对于a[0],a[1]和a[2]来说,a也是数组的名称,是数组的首地址,即FF10。a是指向数组首地址的指针,a+1代表什么?a是数组名称,a[0],a[1]和a[2]是元素,那么a+1就是&a[1](如果一个一维数组int b[3],那么b+1是不是&b[1]?),即第二行元素的首地址,指针值为FF18。同理,a+2就是&a[2],指针值为FF20。 也可以换个角度去理解。a是数组首地址,指向二维数组第一行的首地址;计算a+1时,指针a跳过的是整个a[0],a+1指向二维数组第二行的首地址。指针a在做加法时,跳过的是一行元素。 a[1]+1代表什么?指针a[1]是一维数组a[1]中第一个元素a[1][0]的地址FF18。对于一维数组a[1]来说,指针a[1]+1指向了a[1]中第二个元素a[1][1]的地址,即FF1A。这里指针加法的单位是一列,每次跳过a[1]中的一个数组元素。 *a代表什么?*a也就是*(a+0),数组第一个元素的值,即a[0]。前面讲过,a[0]是一个代号,它不是一个具体元素的值,而是内嵌的一维数组a[0]的名字,a[0]本身也是一个指针值。同理,*(a+1)就是a[1],*(a+2)就是a[2]。 如果要访问二维数组里第i行第j列的某个元素,可以直接引用a[i-1][j-1],也可以使用指针的方法。指向第i行第j列元素的指针为a[i]+j,或者*(a+i)+j,因此,间接用指针引用二维数组里第i行第j列的某个元素,可以表示为*(a[i]+j)或者*(*(a+i)+j)。特别需要指出的是,a[i]不是一个具体的数组元素,它是一个代号,实际上是一个指针值,代表i+1行里中第一个元素的首地址。

指针与数组笔试题

1.请问下面三种变量声明有何区别?请给出具体含义 a)int const *p; b)int* const p; c)int const* const p; 2.在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个 纯粹的ANSI编译器。写代码去完成这一任务。 答:为了访问一绝对地址把一个整型数强制转换(typecast)为一指针; int *ptr; ptr = (int *)0x67a9; *ptr = 0xaa55; 3.下面程序的输出结果是多少? main() { int a[5] = {1,2,3,4,5}; int *ptr = (int*)(&a+1); printf("%d %d" , *(a+1), *(ptr-1) ); } 答:2 5 4.下面程序的输出结果是多少? void foo(int [][3] ); main() { int a [3][3]= { { 1,2,3} , { 4,5,6},{7,8,9}}; foo(a); printf("%d" , a[2][1]); } void foo( int b[][3]) { ++ b; b[1][1] =9; } 答:9 5.下面程序的输出结果是多少? main() { int a[][3] = { 1,2,3 ,4,5,6}; int (*ptr)[3] =a;

printf("%d %d " ,(*ptr)[1], (*ptr)[2] ); ++ptr; printf("%d %d" ,(*ptr)[1], (*ptr)[2] ); } 答:2 3 5 6 6.这3个函数哪一个最可能引起指针方面的问题 int *f1(void) { int x =10; return(&x); } int *f2(void) { int*ptr; *ptr =10; return ptr; } int *f3(void) { int *ptr; ptr=(int*) malloc(sizeof(int)); return ptr; } 答:f1 和f2 7.下面程序的输出结果是多少? main() { char p; char buf[10] ={ 1,2,3,4,5,6,9,8}; p = (buf+1)[5]; printf("%d" , p); } 答:9

如何在C函数中传递指向二维数组的指针参数

前几日用C编写DSP程序时,遇到一个问题:如何向C函数中传递指向二维数组的指针参数。初接触以为很简单,直接声明一个二维数组,然后把数组名传进去。但是一经编译便报错。后来仔细想了一下,并查找了一些相关资料,发现二维数组在概念上远比一维数组复杂,或者说二维数组以一种晦涩的方式构建在一维数组之上。 先来回顾一下一维数组。一维数组的数组名即为指向该数组的指针,该指针值保存了数组存放在内存中的一块连续区域的起始地址;数组的下标表示了这片内存区域的某存储区相对于起始地址的偏移量。简单来讲就是:指向一维数组的指针,指向数据存放区域的起始位置。 事实上,计算机系统的多维数组其实最终还是以一维数组的形式实现的。就N x M的二维数组来讲,设其数组名为array。指针array 指向一个数组,该数组存放的是一系列指针,这些指针分别指向相应的一维数组,而这些数组中存放的才是我们的数据。 array -> [一维数组指针1] -> [ 一维数组,M长] [一维数组指针2] -> [ 一维数组,M长] …… …… [一维数组指针N] -> [ 一维数组,M长]

由此array是第i个指针变量地址,array[j]则表示相对于第i个指针变量偏移j*sizeof(数组类型)。系统通过这种机制访问了该二维数组的第i行,第j列的内容。 有上述可知,指向二维数组的指针其实是指向“指针变量地址”的指针变量。所以在声明指向二维数组的指针时,用int ** array的形式。 有以下两种方式来对二维数组分配内存: ///// 方法一 #include // 必须包含该头文件,里面定义了malloc的实现 int ** array = malloc( N * sizeof(int *) ); for (int k=0;k int ** array = malloc( N * sizeof(int *) ); array[0] = malloc( M * sizeof(int) ); for (int k=1;k

C语言程序设计--二维数组与指针

二维数组与指针(教程) 二维数组与指针 1.二维数组元素在内存中的存放方式 在C++中,二维数组元素值在内存中是按行的顺序存放的。若定义二维整型数组a[3][3],假设编译系统为数组a分配的内存空间从1000开始到1035为止,则数组中各元素a[0][0]~a[2][2]在内存中按行存放次序如图7.6所示。因此,与一维数组类似,可用指针变量来访问二维数组元素。 【例7.7】用指针变量输出二维数组各元素的值。  # include  void main(void)  { int a[3][3]={{1,2,3},{4,5,6},{7,8,9}}; int *p=&a[0][0]; //将二维数组首地址赋给指针变量p for (int i=0;i<9;i++) { cout<<*p<<'\t'; //输出二维数组中第i个元素值 p++; //指针变量p加1,指向下一个元素 }  } 程序执行后输出结果为: 1 2 3 4 5 6 7 8 9 但要用上述指针变量p访问二维数组中任意指定元素a[i][j]就觉得很不方便,为此C++设计者提供另外几种访问二维数组元素的方法,为了了解访问二维数组元素的方法,必须了解三个地址概念,即:二维数组行首地址、行地址、元素地址,现介绍如下。 2.二维数组行首地址 二维数组各元素按行排列可写成如图7.7所示矩阵形式,若将第i行中的元素a[i][0]、a[i][1]、a[i][2]组成一维数组a[i] (i=0,1,2),则二维数组a[3][3]可看成是由三个一维数组元素a[0]、a[1]、a[2]组成。即:a[3][3]= (a[0],a[1],a[2]),其中:a[0]、a[1]、a[2]是分别表示二维数组a[3][3]的

C语言程序设计(第3版)何钦铭 颜 晖 第11章 指针进阶

第11章指针进阶 【练习11-1】如何理解指针数组,它与指针、数组有何关系?为何可以用二级指针数组进行操作? 解答: 指针数组——存放指针的一个数组。 指针数组名也是指向常量二级指针,因为指针数组名总是指向数组的第一个元素。 【练习11-2】用指针数组处理多个字符串有何优势?可以直接输入多个字符串给为初始化的指针数组吗?为什么? 解答: C语言中字符串的地址是按顺序存放的,用指针指向字符串的首地址,然后取出这个地址里面的值,然后指针加一,取出里面的值,这样就能输出整个字符串了。用指针数组可以接收多个字符串,对这些字符串的操作可以做到相互隔离,一个指针数组的元素作为一个指针对应一个字符串。 【练习11-3】参考例11-3,使用二级指针操作改写例11-4中的程序A。 解答: #include #include void fsort(char **ch,int n); int main(void) { int i; char *pcolor[]={"red","blue","yellow","green","black"}; char **ch; ch=pcolor; fsort(ch,5); for(i=0;i<5;i++) printf("%s ",*(ch+i)); return 0; } void fsort(char **ch,int n) { int k,j; char *temp; for(k=1;k0){ temp=*(ch+j); *(ch+j)=*(ch+j+1);

实验11.1 指针数组、指针与函数

实验11.1 指针数组、指针与函数 1 调试示例error11_1.cpp 2 编程题 3 编程题 4 计算最长的字符串长度 5 字符串的连接 6 指定位置输出字符串 7 藏尾诗 8 改错题error11_2.cpp 1 调试示例error11_1.cpp /*---程序填空,不要改变与输入输出有关的语句。输入若干有关颜色的英文单词,以#作为输入结束标志,对这些单词升序排列后输出。其中颜色的英文单词数数小于20个,颜色的英文单词长度均不超过10个字符。 输入: Red blue yellow green purple # 输出:blue green purple red yellow ------*/ #include #include #include void main() { int i,j, n = 0,index; char *color[20], str[10], *temp; scanf("%s", str); while(str[0] != '#') { color[n] = (char *)malloc(sizeof(char)*(strlen(str)+1)); strcpy(color[n], str); n++; scanf("%s", str); } for(i=0;i

C++数组指针题(含答案)

数组指针01:逆序输出 从键盘输入n个整数(n<100),存放在一个一维数组中,逆序输出能被3整除的元素,并逆序输出数组下标为3的倍数的元素。 输入格式:第一个整数为个数n,后续为n个整数 输出格式:第一行能被3整除的元素,第二行为下标为3的倍数的元素,各个数值之间用空格分隔。 输入:10 2 7 9 10 5 4 3 6 8 20 输出: 6 3 9 20 3 10 2 #include using namespace std; const int MAX=100; int main() { int a[MAX],n,i; cin>>n;

for(i=0;i>a[i]; for(i=n-1;i>=0;i--) if(a[i]%3==0) cout<=0;i--) if(i%3==0) cout<

输出格式:下标为3的倍数的元素,各个数值之间用空格分隔。输入:10 2 7 9 10 5 4 3 6 8 20 输出:20 3 10 2 #include using namespace std; const int MAX=100; int main() { int a[MAX],b[MAX],n,i; cin>>n; for(i=0;i>a[i]; b[n-1-i]=a[i]; } for(i=0;i

相关主题
文本预览
相关文档 最新文档