我正在学习指针,但我被下面的示例程序所困扰。它应该是char**
到char*
的转换,但我不理解该程序背后的逻辑。该计划在做什么?
#include <iostream>
using namespace std;
int main() {
char *notes[] = {"cpp","python","java","mariadb"};
void * base = notes; // notes and base, holds the address of note's first element
void * elemAddr = (char*) base + 3* sizeof(char *); // i didn't understand this line???
cout << *(char **)elemAddr; // and this line
return 0;
}
答案 0 :(得分:5)
这些行:
char *notes[] = {"cpp","python","java","mariadb"};
void * base = notes;
void * elemAddr = (char*) base + 3* sizeof(char *);
cout << *(char **)elemAddr;
是一个模糊的等价物:
char *notes[] = {"cpp","python","java","mariadb"};
cout << notes[3];
<强>解释强>
void * base = notes;
void * elemAddr = (char*) base + 3* sizeof(char *);
与:
相同char * base = (char*)notes;
char * elemAddr = base + 3 * sizeof(char *);
由于指针通常具有相同的大小,因此这些行与:
相同char ** base = notes;
char ** elemAddr = base + 3;
使得elemAddr == ¬es[3]
。这导致了
cout << *(char **)elemAddr;
与
相同cout << notes[3];
答案 1 :(得分:2)
好的,我会咬人:
char *notes[] = {"cpp","python","java","mariadb"};
声明指向char *
的指针数组。 (实际应该是const char *notes[]
,因为我们无法修改内容)
void * base = notes; // notes and base, holds the address of note's first element
因此,将数组notes
的地址分配给base
,并在此过程中丢失任何类型信息。
void * elemAddr = (char*) base + 3* sizeof(char *); // i didn't understand this line???
将base
投射到char *
,这意味着每个元素现在都是sizeof(char) == 1
。将3 * sizeof(char *)
添加到该指针 - &gt;将3个元素放入notes
数组中,并将其分配回elemAddr
。
cout << *(char **)elemAddr; // and this line
由于elemAddr
指向notes
中的一个元素,即char*
,它实际上是指向char
指针的指针,我们要打印它指向的是什么,因此最初是*
。
它的可读性不高,编写
会更简单const char* notes[] = { ... };
cout << notes[3];
但是你不会在这里张贴......
答案 2 :(得分:2)
显然,示例代码旨在说明使用数组索引时发生的事情。
重复代码(就像我写这篇文章时那样):
#include <iostream>
using namespace std;
int main() {
char *notes[] = {"cpp","python","java","mariadb"};
void * base = notes; // notes and base, holds the address of note's first element
void * elemAddr = (char*) base + 3* sizeof(char *); // i didn't understand this line???
cout << *(char **)elemAddr; // and this line
return 0;
}
首先,声明
char *notes[] = {"cpp","python","java","mariadb"};
声明一个指向char
的指针数组。每个指针都用字符串文字初始化。这个语言特性在最初的C ++标准C ++ 98中已被弃用,并最终在C ++ 11中删除,因此使用现代C ++(在编写C ++ 14时),它只是无效代码,不能用符合的编译器编译的代码。
在标准C ++中,它可能是
char const *notes[] = {"cpp","python","java","mariadb"};
但是让我们忽略const
问题,并假设C ++ 03或C ++ 98。
然后声明
void * base = notes;
声明一个名为void*
的{{1}}指针,初始化为数组base
的第一项的地址。这可以通过数组表达式 decay 来实现,其中引用数组的表达式会生成指向其第一个项目的指针。
声明
notes
显然是为了说明
中void * elemAddr = (char*) base + 3* sizeof(char *);
索引的幕后情况
[3]
这适用于面向字节的地址算法(auto p = & notes[3];
,其变体是最小可寻址单元的C ++概念,即.k.a。字节)。从数组的基址开始,每个项的大小增加3倍。这将使你在第3项开始时落地。
最后,表达式
char
使用该项目。由于使用低级别类型,它只是丑陋。但实际上,该项目是*(char **)elemAddr
,因此项目的地址被转换为char*
,然后该指针被解除引用,产生char**
指针本身,这是表达式(并传递给char*
)。
答案 3 :(得分:0)
第三行说: “将base转换为char指针,并将char指针大小的3倍添加到结果中。然后,隐式地将结果转换为void指针并将其存储在elemAddr中”
最后,elemAddr指向“mariadb”的地址。转换为(char *)不需要执行指针运算,但它会阻止编译器打印警告。它相当于
¬es[3]
第四行告诉编译器将指针解释为指向char指针的指针。然后取消引用此指针,以便elemAddr指向的数据被视为char指针,它将被std :: cout解释为C字符串。
我不知道你从哪里得到这个例子,但是这种类型的编程对于非常可怕的错误和难以调试的代码来说都是一个蜜罐。
答案 4 :(得分:0)
让我们一行一行: 第一行:我们创建一个指向字符串数组的指针...这是一个指向数组基址的指针......指针。
第二行:我们将char *变为void *,这根本不会改变指针的值,只是编译器与它关联的类型。
第3行:当我们操作基指针时,我们将它转换为char *,基本上撤消我们在第2行所做的操作。我们将3 * sizeof(char *)添加到指针。这使得指向指针数组基础的指针现在指向数组中的第4个指针。
第4行:现在我们加倍deference我们的指针,我们的指针指向什么?指针数组中的第三个元素。那个指针指向什么?字符串在第一行创建。