S1E23:指针数组和数组指针 课后作业

测试题:Powered by
0. 请问 str[3] 和 *(str + 3) 是否完全等价?

答:等价

答案:完全等价。
解析:在 C 语言中,数组名是被作为指针来处理的。更确切的说,数组名就是指向数组第一个元素的指针,而数组索引就是距离第一个元素的偏移量。这也解释了为什么在 C 语言中数组下标是从 0 开始计数的,因为这样它的索引可以对应到偏移量上。因此,str[3] 和 3[str] 是相同的,因为它们在编译器的内部都会被解释为 *(str + 3)。

1. 请问下边代码是否可以正常执行?如果可以,会打印什么值?如果不行,请说明原因?

#include <stdio.h>

int main()
{
        int a[5] = {1, 2, 3, 4, 5};
        int *b;

        b = &a[3];
        printf("%d\n", b[-2]);

        return 0;
}

答:不能(错误),答案为2

答案:可以正常执行。
解析:数组的下标法跟指针法访问是等价的,所以 b[-2] 相当于 *(b - 2),这样也就不难理解啦^_^T

2. 为什么不能使用 if (str1 == str2) 这样的形式来比较两个字符串?

答:这是两个地址,不能做比较

答案:因为这样比较的是指向两个字符串的指针,而不是字符串本身。

3. 通常我们交换两个变量的值需要使用到一个临时变量,代码如下:

……
temp = a;
a = b;
b = temp;
……

小明童鞋说其实大可不必使用临时变量,他这么写:

……
a += b;
b = a - b;
a -= b;
……

请问小明的办法可行吗?

答:可以,但我觉得只有大聪明会这么写

答案:在大部分情况下,小明的方案是奏效的。不过有一种情况需要担心,就是在颠倒同一个变量时,这个代码是无法正常运行的。

……
#define SWAP(a, b) (a += b, b = a - b, a -= b)
……
int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i, j;
……
SWAP(array[i], array[j]);  // 当 i == j 时,触发 Bug
……

4. 如果数组 array 的定义如下:

int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

请问 array 和 &array 有区别吗?

答:有区别,array为数组的地址,&array为array的地址(分析错误,详情见答案

答案:有。
解析:虽然 array 和 &array 的值相同,但含义是不一样的。array 表示数组第一个元素的位置,而 &array 表示的是整个数组的位置(这里将数组看做一个整体)。

5. 如果不上机,你能看出下边代码将打印什么值吗?

#include <stdio.h>

int main()
{
        int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        int *p = (int *)(&array + 1);

        printf("%d\n", *(p - 6));

        return 0;
}

答:&array的地址不清楚指向,猜想  *(p-6)= 3(错误

答案:4
解析:首先你要明白虽然 array 和 &array 的值相同,但含义是不一样的。array 表示数组第一个元素的位置,而 &array 表示的是整个数组的位置(这里将数组看做一个整体)。
因此,&array + 1 指向的就是整个数组最后的位置(第二个 array 数组的起始位置),然后 (int *) 将其强制转换为一个整型地址(指针),所以指针变量 p 初始化后,指向的地址应该是 array[10](第 11 个元素),所以 *(p - 6) == array[10 - 6] == array[4] == 4。
重点强调:array 是数组第一个元素的地址,所以 array + 1 指向数组第二个元素;&array 是整个数组的地址,所以 &array + 1 指向整个数组最后的位置。

6. 如果不上机,你能看出下边代码将打印什么值吗?

#include <stdio.h>

int main()
{
        int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        int (*p)[10] = &array;

        printf("%d\n", *(*(p+1)-6));

        return 0;
}

答:4

答案:4
解析:基本上一道题成功理解的话,这道题就不会有什么问题。指针 p 指向数组 array 的地址,p + 1 便是指向整个数组最后的位置(第二个 array 数组的起始位置),于是 *(p+1) 即下一个数组 array 数组的起始位置,即 &array[11],所以 *(*(p+1)-6) == array[11 - 6] = array[5]。
PS:如果我把打印的代码写成这样 printf("%d\n", (*(p + 1))[-6]); 现在你应该也可以理解了吧!

7. 你如何理解“指针的类型决定了指针的视野,指针的视野决定了指针的步长”这句话?A

答:我不太清楚(错误

答案:你必须清楚一个指针变量将告诉我们两个信息:某个数据结构的起始地址,以及该结构的跨度。比如 int p = &a; 说明该指针指向变量 a 的起始地址,以及它的跨度为 sizeof(int)。所以 p + 1 == p + sizeof(int)。
怕大家不够清晰,我接着给大家讲上一题(第 4 题)……同样的道理,int (*p)[10] 虽然是定义一个整型指针,但不要忘了它后边还有一个数组,所以它的跨度应该是 sizeof(int) * 10,而 array 作为数组名,它的含义是“指向数组第一个元素的地址”,所以 array 的跨度是 sizeof(array[0]),因此编译系统遇到 int (*p)[10] = array; 这样的定义就会果断报错:“左右类型不一致”。
追问:那 &array 怎么可以?
追答:天啊,快点忘掉 &array 的值等于 array 这一回事儿吧(你会这么想完全是因为这个)……因为 &array 是整个数组的地址,所以它的跨度自然而然就是整个数组啦。

动动手:
0. 现学现用:本道题要求你快速学会一个新的技巧并独立完成练习。T
教学篇 
我们前面使用的 main 函数都是不带参数的,所以 main 后的括号都是空括号:

int main()
{
        ……
}

实际上,main 函数是可以带参数的,这个参数可以认为是 main 函数的形参(形式参数)。C 语言规定 main 函数的参数只能有两个,习惯上把这两个参数写为 argc 和 argv。
C 语言还规定C语言还规定了argc(第一个形参)必须是整型变量,argv(第二个形参)必须是指向字符指针的指针(注意:它不是指针数组,但你可以理解为指向一个字符指针数组名或字符串数组,在函数章节我们将详细讲解,这里只要求你能够根据案例模仿实现即可)。
因此,main 函数可以写成下边这样:

int main (int argc,char *argv[])
{
        ……
}

我们知道 main 函数是由系统进行调用的(我们自己无法调用它),那么如何给它传递参数呢?
其实我觉得你们应该猜到了,main 函数的参数是从命令行上接收的。
举个例子大家就明白了,看代码:

#include <stdio.h>

int main(int argc, char *argv[])
{
        int i;

        for (i = 0; i < argc; i++)
        {
                printf("%s\n", argv[i]);
        }

        return 0;
}

编译的时候指定输出的文件名:

gcc test.c -o test

观察下边几种执行程序的方式:

对比一下代码,大家就应该不难发现:argc 参数指定的是程序的参数数量(包括程序名本身),而 argv 这个指针数组指向的则是每个参数的名字(字符串)。"
好了,新技能Get√就到这里结束,大家开始做练习!
写一个叫 sum 的程序,计算后边紧跟着的所有整型参数的和。
提示:如果你不希望自己实现字符串到整数的转换,可以使用 atoi 函数
程序实现如下:P

答:我用的dev c++,实现不了gcc编译器的操作(错误

#include <stdio.h>

int main(int argc, char *argv[])
{
	int i,sum=0;
	
	for(i=0; i<argc; i++)
	{
		sum = sum + (int)(*wargv[i]);
	}
	printf("sun = %d\n",sum);
	
}

答案:(理解不了答案)

#include <stdio.h>

int main(int argc, char *argv[])
{
        int result = 0;

        while (argc-- != 1)
        {
                result += atoi(argv[argc]);
        }

        printf("sum = %d\n", result);

        return 0;
}


Ij1. 虽然你们看到这道题可能会很想扁我……但这道题只有真正理解指针数组和数组指针的童鞋才能正确实现,一头雾水的童鞋请回顾下相关概念吧X
填充空白部分的代码:
Ij@[`8aH+bNJ K#&sOfUk%crLgP,p7

要求实现结果如下:

答:答不出来(错误

答案:(还能这么操作?直接多加一维度的数组?)

#include <stdio.h>

int main()
{
        char *array[5] = {"FishC", "Five", "Star", "Good", "WoW"};
        char *(*p)[5] = &array;
        int i, j;

        for (i = 0; i < 5; i++)
        {
                for (j = 0; (*p)[i][j] != '\0'; j++)
                {
                        printf("%c ", (*p)[i][j]);
                }
                printf("\n");
        }

        return 0;
}

解析:其实这道题是按照课堂上的代码”依葫芦画瓢“,仔细推敲并不难理解。我们只是把整型变成了字符指针类型(即指向字符串第一个字符的指针),所以定义数组指针的时候,类型改为 char *,索引时只需要在原来的基础上使用下标法或指针法,即可打印出字符串的每个字符。
当然,根据下标法和指针法可以互换的原理,代码也可以这么写:

(  *(*p+i) 为 (*p)[i]  )

#include <stdio.h>

int main()
{
        char *array[5] = {"FishC", "Five", "Star", "Good", "WoW"};
        char *(*p)[5] = &array;
        int i, j;

        for (i = 0; i < 5; i++)
        {
                for (j = 0; *(*(*p + i) + j) != '\0'; j++)
                {
                        printf("%c ", *(*(*p + i) + j));
                }
                printf("\n");
        }

        return 0;
}

2. 修改上一题的代码,要求按下边格式输出:

代码清单:

#include <stdio.h>
#include <string.h>

int main()
{
        char *array[5] = {"FishC", "Five", "Star", "Good", "Wow"};
        char *(*p)[5] = &array;
        int i, j;

        for (i = 0; i < 5; i++)
        {
                for (j = 0; j < 5; j++)
                {
                        if (i > strlen((*p)[j]) - 1)
                        {
                                break;
                        }
                        printf("%c ", (*p)[j][i]);
                }
                printf("\n");
        }

        return 0;
}

答:答不出来(错误

答案:

解析:矩阵转置还记得吗?(我们在讲二维数组时候讲过哦~),只需要简单的将 i 和 j 两个循环变量调换一下位置即可实现。
不过这道题还要考察你的细心程度,像下边这么写就会造成字符数组的越界访问:

#include <stdio.h>

int main()
{
        char *array[5] = {"FishC", "Five", "Star", "Good", "Wow"};
        char *(*p)[5] = &array;
        int i, j;

        for (i = 0; i < 5; i++)
        {
                for (j = 0; j < 5; j++)
                {
                        if ((*p)[j][i] == '\0')
                        {
                                break;
                        }
                        printf("%c ", (*p)[j][i]);
                }
                printf("\n");
        }

        return 0;
}

  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值