再分享一道笔试题

Another Written Exam Question

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;

int main(){

int a[] = {1,2,3,4,5};
int* p = (int*)(&a + 1);

cout << *(a+1) << ',' << *(p-1) << endl;

return 0;
}

问此程序的输出是多少?

错误答案是 2,1

What is the output of this program?

The wrong answer is 2,1

正确答案是 2,5

哎,发现学的多了前面的知识点就忘没了,每天多线程多进程的,却连数组指针都忘记了。

知识点

本题考查的知识点是数组指针,网上的教程和博客通常把数组指针和指针数组一起介绍。我这里也就一起介绍了。

什么是数组指针?

指向数组指针

首先,它是一个指针,指向的对象是数组。我们知道对一个对象取地址,可以得到这种对象类型的指针,因此,题目种对数组 a 取地址(&a)所得到的结果类型就是数组指针。这个数组指针所指向的对象数组的大小是5个int,因此,当这个指针加一的时候指针的偏移量是所指对象的大小(5个int),再将其强制转换为(int*)整型指针并赋值给变量 p ,此时 p - 1指向的就是元素 5 的地址。

image-20220414132405018

那什么是指针数组呢?

元素是指针数组

两者定义方式不同

The correct answer is 2,5

Alas, I found that as I learned more, I forgot the earlier knowledge points. I deal with multithreading and multiprocessing every day, yet I even forgot about array pointers.

Knowledge Points

This question tests the knowledge point of array pointers. Online tutorials and blogs usually introduce array pointers together with pointer arrays. I’ll do the same here.

What is an array pointer?

A pointer to an array

First, it is a pointer, and the object it points to is an array. We know that taking the address of an object yields a pointer of that object type. Therefore, in this problem, taking the address of array a (&a) gives a result of type array pointer. The array pointed to by this array pointer contains 5 ints, so when this pointer is incremented by one, the offset is the size of the pointed-to object (5 ints). After casting it to an int* integer pointer and assigning it to variable p, p - 1 now points to the address of element 5.

image-20220414132405018

Then what is a pointer array?

An array whose elements are pointers

The two are defined differently

1
2
3
4
5
// 数组指针
int (*p)[3]; // p 指向一个 包括3个整型数据的 数组

// 指针数组
const char* p[3] = {"wang","guang","xin"}; // 数组 p 包含三个const char* 类型的指针

二者的用途

首先说指针数组,因为这个的用途非常非常常见,毫不夸张地说,我们的每一个程序都显式或隐式的使用了它。😏

那就是主函数参数。

Their Uses

Let’s talk about pointer arrays first, because their use is extremely, extremely common. It is no exaggeration to say that every one of our programs uses them explicitly or implicitly. 😏

That is, the main function parameters.

1
2
3
4
int main(int argc,char* argv[]){ 
// 第二个参数就是指针数组 第一个参数是数组的长度
return 0;
}

由于数组在函数传参的过程中会被弱化成指针类型,指针数组也是数组,所以也适用于这条规则,因此主函数的第一个参数传入数组长度。

指针数组在函数传参时会被弱化成二级指针,因此也有下面这种主函数写法。二者是等价的。

Since arrays decay into pointer types when passed as function arguments, and a pointer array is also an array, this rule applies to it as well — that’s why the first parameter of the main function receives the array length.

Pointer arrays decay into double pointers when passed as function arguments, so there is also the following way of writing the main function. The two are equivalent.

1
2
3
int main(int argc,char** argv){
return 0;
}

接下来说一下数组指针的用途,(说实话我也没想到什么场景一定要用数组指针),函数传参时可以使用数组指针。

比如说传递一个二维数组,就可以用传递一个指针的形式。

Next, let’s talk about the uses of array pointers. (To be honest, I can’t think of any scenario where an array pointer is a must.) Array pointers can be used when passing function arguments.

For example, to pass a two-dimensional array, you can pass it in the form of a pointer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

void func(int (*p)[2][3]){
cout << "第一行第一个元素:" << (*p)[0][0] << endl;
cout << "第二行第一个元素:" << (*p)[1][0] << endl;
cout << "最后一个元素:" << *((int*)(p+1)-1) << endl;

}

int main(){
int a[][3] = {{1,2,3},{4,5,6}};
func(&a);
return 0;
}

自测题

分别计算下列程序的输出 ,答案在最后

第一题

Self-test Questions

Calculate the output of the following programs separately; the answers are at the end.

Question 1

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
int main(){
int a[][3] = {1,2,3,4,5,6};
int* p = (int*)(&a+1);
int* q = (int*)(a+1);
int* r = (int*)a + 1;
cout << *(p-1) << endl << *(q) << endl << *(r) << endl;
return 0;
}

第二题

Question 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 64 位
#include <iostream>
using namespace std;

void func(int (*p)[3]){
cout << sizeof(p) << endl;
cout << sizeof(*p) << endl;
cout << sizeof(**p) << endl;
}


int main(){
int a[] = {1,2,3};
func(&a);

return 0;
}

第三题

Question 3

1
2
3
4
5
6
7
8
9
10
11
12
// 64 位
#include <iostream>
using namespace std;

int main(){
int* a[3] = {0};
cout << sizeof(a) << endl;
cout << sizeof(*a) << endl;
cout << sizeof(**a) << endl;

return 0;
}

答案:

第一题

Answers:

Question 1

1
2
3
6
4
2

第二题

Question 2

1
2
3
8
12
4

第三题

Question 3

1
2
3
24
8
4

PS:64 位编译器下一个指针 8 个字节,一个 int 4 个字节。

以上答案为 OnlineGDB 的运行结果,不同环境下运行结果可能不同,主要是指针大小的不同。

欢迎留言指出文中错误之处。

PS: on a 64-bit compiler, a pointer is 8 bytes and an int is 4 bytes.

The answers above are the results of running on OnlineGDB; results may differ in different environments, mainly due to different pointer sizes.

Feel free to leave a comment pointing out any errors in this article.