多维数组与指针
二维数组 a[3][4] , 可以看作是有三个以一维数组为元素的数组,这三个一维数组的数组名分别是 a[0], a[1] 和 a[2] 。
数组名 a ,为数组首地址,即其第一个元素(一维数组)的地址,指向第一个元素(一维数组), a+1 指向第二个元素(第二个一维数组), a+2 指向 a[2]
又由于 a[0], a[1] 和 a[2] 为一 维数组,故它们也是数组的首地址。 a[0] 是第一个 一 维数组的数组名,即它是第 1 行第 1 个元素 a[0][0] 的地址,a[0]+1
指向 a[0][1], *(a[0]+1) 是 a[0][1] 的值。 也即,不管 二维数组还是 一维数组,它们的数组名都是数组的首地址,都指向数组的第一个元素,只不过,对二维数组
来说,数组名指向的是一个 一维数组(地址),而不是一具体数值;而对 一维数组来说,数组名指向的是一 具体数值,而不是一 个 地址。应特别注意的是 a,a[0]
都是地址,且数值是相同的,但 a 指向一维数组,而 a[0] 指向一个整型数值,它们的类型是不同的,所以 a+1 与 a[0]+1 的含义不但不同,数值也是不一样的。
1. 多维数组的地址
通过上面的讨论,我们直接得到以下结论:
对 a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}
|
a 是 二维数组的名字,是二维数组的首地址,即第 0 行的首地址
a+1 是数组 a 第 1 行首地址
a[0],a[1],a[2] 是二维数组中三个一维数组的名字(地址),是第 0 行第 1 个 ,第 1 行第 1 个 ,第 2 行第 1 个元素 的首地址。
a[i]+j 是第 i 行 j 列的地址
*(a[i]+j) 是该地址存储的值,即 a[i][j]
a+1 以行为单位移动,而 a[I]+1 在同一行以列(一个元素)为单位移动,所以 a+I 是行指针, a[I] 是列指针,a+1 是个指针,指向第一行的一维数组,那么
*(a+1) 就是个一维数组(的数组名),而第一行的一维数组的数组名是 a[1], 所以 *(a+1)=a[1], 也即 *(a+1) 指向了数组元素 a[1][0] ,变成了一个列指针,可
见对行指针进行 * 运算,就变成了列指针
同理 a[1] 是数组名, &a[1] 表示指向该数组的一个指针,即 a+1, 可见对列指针(数组名)取地址,就得到一个行指针,也即指向一个一维数组的指针。
大家思考一下 *(a+1)+1 和 *(*(a+1)+1) 的含义
大家再思考一下 &a[1][0] 和 &(&a[1][0]) 的含义
可以得到一个结论,对行指针进行一次 * 运算,它将变成列指针,进行两次 * 运算,它将变成一个数值
同理,对数组元素进行一次 & 运算,它得到一个列指针,进行两次 & 运算,将得到一个行指针
现在再来看以下式子的含义:
a, *a, **a
a+1, &a[1]
a[1], *(a+1)
a[1]+2, *(a+1)+2, &a[1][2]
*(a[1]+2), *(*(a+1)+2), a[1][2]
大家思考以下,下列式子值是否相同,含义是否也相同
a, *a, a[0], &a[0][0]
a+1, *(a+1), a[1], *(a[1])
*(a[I]+j), *(*(a+I)+j), a[i][j]
|
总结: 1. 二维数组名,指向一维数组的指针,行指针 三者等价 2. 一维数组名,指向具体元素的指针,列指针 三者等价 3. 行指针加 * ,变成列指针,行指针加 ** ,变成元素 4. 列指针加 * ,变成列元素,列指针加 & , 变成行指针 也即行指针、列指针、元素通过 [* , &] 两个运算符号,可以相互转化 |
|
2. 指向一维数组的指针
定义格式: 类型说明符 (*变量名)[常量表达式]
如: int (*p)[4]; 定义了一个指针变量,它指向一有 4 个整型元素的数组
|
[ 例 ] 输出二维数组任一行任一列元素的值 。 | |
|
{ int a[3][4]={ {1,3,5,7}, {9,11,13,15}, {17,19,21,23} }; int (*p)[4], i, j ; p=a; scanf(“%d , %d”, &i,&j); printf(“a[%d][%d]=%d\n”,i,j,*(*(p+i)+j)); } |
3. 用指向数组的指针作函数参数
一维数组名可以作为函数参数传递,多维数组名也可作为函数参数传递,多维数组作为函数参数传递时,可有多种形式,只要它们的意思正确即可。
|
[ 例 ] 三个学生及其每个学生四门课程的成绩已放在二维数 组 A[3][4]={{66,57,70,86},{58,67,90,45}, {98,67,87,95}} 中,从键盘输入一个学生的学号,输出该学生四门课程成绩的均分。 | |
|
void aver1(int a[3][4],int n); void aver2(int *p); void aver3(int (*p)[]); main() { int a[3][4]={{66,57,70,86},{58,67, 90, 45},{98,67,87,95}} , n; clrscr(); printf(“please input n:”, n); scanf(“%d”, p); aver1(a,n); /* 上面一句与下面两句中的任意一句等价 aver2(&a[n-1][0]); aver3(&a[n-1]); */ getch(); } void aver1(int a[3][4], int n) { int s=0, I; float aver; for (I=0; I<4; I++) { s=s+a[n-1][I]; } aver=s/4.0; printf(“aver=%d\n”, aver); } void aver2(int *p) { int s=0, I; float aver; for (I=0; I<4; I++) { s=s+p[I]; } aver=s/4.0; printf(“aver=%d\n”, aver); } void aver3(int (*p)[]) { int s=0, I; float aver; for (I=0; I<4; I++) { s=s+(*p)[I]; } aver=s/4.0; printf(“aver=%d\n”, aver); } |
一、字符串的两种处理方式
1. 字符数组方式
字符串的定义、输入、输出、和引用
|
[ 例 1] 读下面的程序说出结果。 | |
|
{ char str1[80]={“How are you!”}; char str2[80]; clrscr(); printf(“please a String: ”); scanf(“%s”, str2); printf(“%s\n”, str1); printf(“%s\n”, str2); getch(); } |
2. 字符指针方式
|
[ 例 2] 读下面的程序说出结果。 | |
|
{ char *p = “How are you!”; clrscr(); printf(“%s\n”,p); getch(); } |
|
[ 例 3] 读下面的程序。 | |
|
{ char str[80]; char *p; clrscr(); p=str printf(“please a String: ”); scanf(“%s”, p); printf(“%s\n”, p); getch(); } |
|
[ 例 4] 读下面的程序,判断有无错误。 | |
|
{ char *p1=“How are you!”; char *p2; clrscr(); printf(“please a String: ”); scanf(“%s”, p2); printf(“%s\n”, str1); printf(“%s\n”, str2); getch(); } |
3. 总结和说明
( 1 ) 正确理解 printf(“%s”, str) 的含义
( 2 ) 正确理解下面几个式子
char str[80]= “ How are you”
char *p = “ How are you” // 让 p 指向字符 'H'
p= “How do you do ”; //p 为字符串的首地址
str= “How do you do ”; // 错误
请记住,数组名是地址常量,与指针变量是不一样的。
( 3 ) 指针定义时,若无初始化,则他指向的存储单元未知。
( 4 ) 函数中出现字符串的地方,都可以用字符指针代替。
4. 关于几个函数的说明
printf(char *str, ...)
scanf(char *str, ...)
strlen(char *str)
strcpy(char *str)
strcat(char *str)
|
[ 例 5] 读下面的程序说出结果。 | |
|
{ char *p1, *p2;; int a, b; clrscr(); p1=”%d,%d”; p2=“a=%d b=%d\n”; printf(“please a , b: ”); scanf(p1, p2); printf(p2, a, b); getch(); } |
本文详细解析了多维数组与指针之间的关系,包括如何理解二维数组的地址与指针,以及一维数组指针的定义和使用。并通过实例展示了如何利用指向数组的指针作为函数参数来操作数据。
1566

被折叠的 条评论
为什么被折叠?



