用另一个数组初始化指向数组的指针
Point of initializing a pointer to an array with another array
这个指向数组的指针是用另一个数组初始化的。它试图完成什么?
float range_[] = {0, 180};
const float* range[] = {range_};
我正在尝试将它们合并成一个 class,而 C++ 对将可变长度数组放入 classes 很挑剔,所以我需要一些等效的东西,但我不知道它在做什么
这个怎么样:让我们说出关于该演示代码不想知道的一切。就演示代码而言,这非常具有挑衅性。它直击作家的障碍,强大到足以释放出滔滔不绝的话语,让大坝坍塌感觉就像国际空间站的轨道船员观察到的那样可怕。几百英里的真空当然可以提供一个视角。
但我们不应该对此刻薄。好吧,我不能。有人写了那个演示代码,万一是我(谁知道我写的演示代码我不记得了)——对自己刻薄是不行的。所以我们还是放轻松吧。
range
是一个指针数组。但无论如何你都不应该使用其中的任何一个,很有可能。
您的可变长度数组有一个名称:std::vector
。就用那个。效果很好。
但是回到指针等:指针数组就像一个非常精简的地址簿。每个指针都是某人或某物的地址。当你只有一个地址簿时,你的朋友就没有了。你只有他们的地址。您也可能碰巧拥有这些朋友的家,然后地址簿会列出您拥有的财产。但这需要购买土地。或者,用编程语言来说:内存分配和所有权。
因此,为了获得地址,首先需要有人购买土地。必须分配一些内存,然后你可以把它的地址放在地址簿中。第一个在第 0 页(索引 0),第二个在第 1 页,依此类推。
至于代码试图完成什么:也许是愚蠢的事情?
float range_[] = {0, 100};
第一行很明显:这是一块土地。两英亩。其中一英亩土地上有一座巨大的零雕塑——离你较近的那块土地。 100 的雕塑在另一英亩的土地上。还没有全部写出来——编译器"fills in the blank"。第一行 really 意思是:
float range_[2] = {0, 100};
现在到第二行:
const float* range[] = {range_};
您现在可能知道它的去向:让我们填空:
const float* range[1] = {range_};
第二行是那个通讯录。它还需要一些 space:毕竟,即使是地址簿也放不下零英亩土地。什么都不会。所以你需要比没有 space 多一点来存储地址簿,但它可以比它保存地址的东西小得多。即使英亩面积相对较小(float
s 一点也不宽敞,就目前而言)。并且地址簿只能容纳一个地址,该地址是占地两英亩的地块,上面有两个数字雕塑。但是等等:地址簿上的地址只字未提两英亩。它只是说它是一些英亩的地址。它甚至可能是一个没有任何英亩的地址。这样的地址用nullptr
表示。
通讯录还有个注解,禁止乱动那块地。在 C 语言中,它是指向常量值的指针。或者一堆常量值。或者 none。看看指针在哪里?真的很难知道你在做什么是否合适。这是某人的地址,好吧 - 也许吧。它可能没有地址,也可能是挤满整个学校实地考察学生的旅馆的地址,或者可能是一个空的 phone 摊位的地址。你不相信我?这里:
double phoneBooth = std::nan("empty");
double *i_hope_my_friends_are_there = &phoneBooth;
这是真正的 C++。它编译。这和我说的差不多。如果您需要表示一个空的 phone 展位,而您得到的只是一个双人展位,它会在紧要关头完成。您可能希望将其放入一些演示代码中以增加效果。所以,现在你明白为什么指针会很糟糕了。和双打。双打当然很糟糕,但花车更糟糕。哦 - 除非你是大型机程序员。那么这应该是非常熟悉的:
float pbth = nan("MPT");
也是真正的 C++ 代码,除了有人把 using namespace std
放在更早的地方。对于任何熟悉 COBOL 的人来说,这已经足够罗嗦了。 pbth
的定义与 COBOL 背景形成鲜明对比。散发着 System 360 组装的味道。
但是我们越来越分心了。回到range_
!没有人说拥有 range_
属性 的人会用它做什么。他们可能会炸毁整个地方。你所知道的是 你 被禁止更改 属性 上的任何内容 - 如果你得到的只是那个地址簿。所以 - 也许你确实知道你也确实拥有那块土地,然后你就可以成为炸毁它的人。但是很难判断您是否只有那个地址簿。它只是说:
- 你可以来看看这些雕塑,哦 - 顺便说一下 - 展览会在一天中随机变化,但前提是你不断购买西红柿。 (我保证很快就会有 1% 的意义)
现在稍等一下:为什么给定一个地址簿,您会想到两个维度,只是因为您获得地址的东西本身就有一个维度?你根本不需要那样想。至少(数学家除外),任何人都不会自然而然地想到它。如果您对实际上具有二维(空间、矢量-space-ish 或类似的东西)的问题建模,您只会想那样想。否则,就没有什么“2D”的了。您几乎不会认为矩阵是 "two dimensional" 对象。
如果你有一个真实的地址簿,上面写着你朋友的地址,并且到处说你的地址簿是 4D 的,因为它是一个大概是 3D 的“1D”邮政地址列表 space,人们可能对整件事看起来很滑稽。这不是一个非常实用的观点。除了:它只有在帮助您处理问题时才实用。但不应该仅仅因为其他一些人似乎受到了帮助就认为它对你有帮助是理所当然的。希望这一段的警告中的讽刺意味终于暴露无遗。
实际上,如果您有一个具有离散区域单位 ("squares") 的矩形区域,您会认为它具有二维,但通常最紧凑的存储方式不是分块将其分解成更小的碎片,将它们随风飘荡,查看它们落在附近的哪个位置,并收集它们所在的地址。不幸的是,这就是学生,通常是他们倒霉的教授,期望使用一系列指针的方式。相反,只要得到一个足够大的长块,并保留它的地址。或者甚至更好,将它围起来,种一些西红柿,然后按照您想要的顺序收集它们,让方法处理细节。
现在你的需求可能比这个更花哨,但是只要矩形区域是"small",说比浮动少一百个项目,把它全部放在一个块中并移动元素around 可能是最快的处理方式。我的意思是:如果你关心实际性能,而不是一些数学家关于计算机的影子在执行这样的任务时应该如何表现的想法。很少有广泛使用的实用计算机能够达到这样的理念。
就复杂性理论而言,基于 AVR 的 Arduino 有一些非常明确的影子,您可能会发现链表的行为有点像您在算法课程中学到的东西。但是 运行 在您的 PC 上使用相同的程序,稍微调整一下,您就会遇到极端情况,在这种情况下它的性能可能比在 Arduino 上差。我没骗你——这肯定是一个病态的案例,但它并不难编造。词汇量比我高明得多的人称之为 "a denial of service",但我不确定向人们扔西红柿在多大程度上是不让他们吃饭,而不是说给他们喂西红柿。
然后你重写所述程序,使其在 Arduino 上慢 10 倍,但在 PC 上快数千倍。我绝对不是在开玩笑。
从你的问题回到那个破烂的地址簿:它不是很有用,因为它只有一页,大声喊叫。而且没有办法改变这一点。单页,精装,就是你所拥有的。需要存储更多地址?去拿另一个。您还不如只存储一个地址,而无需存储整个地址簿的繁琐内容。一张纸 - 无需装订工作。它可以是单个地址,而不是具有单个元素的数组。像这样:
const float *range = range_;
但是您当然是在编写 C++。而这一切都是愚蠢的。如果您只需要一块可以轻松调整大小的土地,请使用矢量:
struct MyClass {
std::vector<float> range;
};
它在一个结构中,而不是在 class 中,只是因为它告诉了人类一些东西——对编译器来说,这两者实际上是一回事。它告诉人类的是:这里是 属性。没有监督。你明白了,敞开心扉,你做你想做的。有一台挖掘机,想把这个地方挖出来?往前走。除非它是一个 const struct - 否则它是被禁止的。当然。但不总是。如果对象本身是 const 则禁止。但是如果对象不是 const,但你有一个指向它的指针标记为 "pointer to const",你就有了后门。 const_cast
,开动挖掘机,出发。没关系。不是UB
通常我们保留关键字 class
用于以某种方式管理 属性 的用途。土地会在篱笆后面,一群站在篱笆上的人会卖给你土地上生长的西红柿。如果您当着他们的面称呼他们 methods,他们可能会被冒犯,但在软件工程人员中,这样的谈话是司空见惯的。贬低软件工程的东西。
但是假设您确实想要一个向量的向量:
using A_vector_of_vectors = std::vector<std::vector<float>>;
你拥有城市街区,每个街区都有许多房产。与城市街区一样,这只有在街区有些分离而不是交织在一起并且有些独立的情况下才有意义:它们真正以(或不)自己的速度增长,并且它们的规模需求各不相同。如果你想要总是一起访问的街区,并且它们的大小有一些规则模式(全部相等,或者按算术或几何级数 - 类似的东西),你可能只想要一个大城市街区 - 只划定细分在某种地图上,而不是通过道路工程和绕行等方式进行描绘。
您可以拥有零个或多个城市街区:这是外向量。每个城市街区都可以有任意大小——甚至是零大小。当它的大小为零(为空)时,您所得到的只是一个 "name" - 用来调用它的东西,以便您稍后可以说 "hey, we want the Nomish Quarters sized to fit four nomes, please!"。那就是将一个特定的内部向量增加到 4 的大小。
我们可以用简单的符号表示那些向量和子向量的特定内容。假设有三个向量,第一个没有元素,第二个有一个元素,第三个有两个元素。你会这样写下来:{{}, {50}, {80, 90}}
。很容易。现在我们可以使用它来预填充向量的向量:
struct MyClass {
A_vector_of_vectors vov{{}, {50}, {80, 90}};
};
这是制作MyClass
的秘诀:目前这只是一个柏拉图式的想法。有点像素食炸肉排的食谱,上面装饰着完美无暇的图片。当你第一次制作它们时,它们就很适合做鞋底。不过,随后他们往往很棒。是的,class 不存在,只是一个影子。如果你真的想吃一个,你必须创建一个它的实例:
MyClass anInstance;
现在我们得到了一个小城市,有一组三个城市街区,第一个 0 英亩,第二个 1 英亩,第三个 2 英亩。他们非常乐于助人。您可以调整每一个的大小。您可以重新排列它们的顺序,或其中英亩的顺序。您可以添加新的。删除旧的。最好的事情是什么?你让别人做所有的工作。 std::vector
和编译器会处理细节。当您不再需要 anInstance
时,您只需核对它即可。你结束了范围,所以结束了城市。就这样。
int main() {
MyClass anInstance;
} // bye bye, city
你看,没有 malloc
,没有 free
。番茄人为我们做了这一切!
What is range_ doing tho?
float range_[] = {0, 180};
range_
是两个浮点数的数组。第一个值为 0,另一个值为 180。
const float* range[] = {range_};
range
是一个指向 const float 的指针的数组。它指向 range_
.
的第一个元素
but idk what it's doing
他们什么都不做。它们是数组。它们包含值。
I'm trying to consolidate them into a class, and C++ is finicky about putting variable length arrays in classes
您显示的数组不是可变长度的。一个的大小为 2,另一个的大小为 1。
如果你想使数组成为成员变量,那么你只需在类型中明确指定该大小,而不是从初始化程序中推导。例如:
struct example {
float range_[2];
const float* range[1];
};
也就是说,据我所知,range
数组似乎没什么用。
这个指向数组的指针是用另一个数组初始化的。它试图完成什么?
float range_[] = {0, 180};
const float* range[] = {range_};
我正在尝试将它们合并成一个 class,而 C++ 对将可变长度数组放入 classes 很挑剔,所以我需要一些等效的东西,但我不知道它在做什么
这个怎么样:让我们说出关于该演示代码不想知道的一切。就演示代码而言,这非常具有挑衅性。它直击作家的障碍,强大到足以释放出滔滔不绝的话语,让大坝坍塌感觉就像国际空间站的轨道船员观察到的那样可怕。几百英里的真空当然可以提供一个视角。
但我们不应该对此刻薄。好吧,我不能。有人写了那个演示代码,万一是我(谁知道我写的演示代码我不记得了)——对自己刻薄是不行的。所以我们还是放轻松吧。
range
是一个指针数组。但无论如何你都不应该使用其中的任何一个,很有可能。
您的可变长度数组有一个名称:std::vector
。就用那个。效果很好。
但是回到指针等:指针数组就像一个非常精简的地址簿。每个指针都是某人或某物的地址。当你只有一个地址簿时,你的朋友就没有了。你只有他们的地址。您也可能碰巧拥有这些朋友的家,然后地址簿会列出您拥有的财产。但这需要购买土地。或者,用编程语言来说:内存分配和所有权。
因此,为了获得地址,首先需要有人购买土地。必须分配一些内存,然后你可以把它的地址放在地址簿中。第一个在第 0 页(索引 0),第二个在第 1 页,依此类推。
至于代码试图完成什么:也许是愚蠢的事情?
float range_[] = {0, 100};
第一行很明显:这是一块土地。两英亩。其中一英亩土地上有一座巨大的零雕塑——离你较近的那块土地。 100 的雕塑在另一英亩的土地上。还没有全部写出来——编译器"fills in the blank"。第一行 really 意思是:
float range_[2] = {0, 100};
现在到第二行:
const float* range[] = {range_};
您现在可能知道它的去向:让我们填空:
const float* range[1] = {range_};
第二行是那个通讯录。它还需要一些 space:毕竟,即使是地址簿也放不下零英亩土地。什么都不会。所以你需要比没有 space 多一点来存储地址簿,但它可以比它保存地址的东西小得多。即使英亩面积相对较小(float
s 一点也不宽敞,就目前而言)。并且地址簿只能容纳一个地址,该地址是占地两英亩的地块,上面有两个数字雕塑。但是等等:地址簿上的地址只字未提两英亩。它只是说它是一些英亩的地址。它甚至可能是一个没有任何英亩的地址。这样的地址用nullptr
表示。
通讯录还有个注解,禁止乱动那块地。在 C 语言中,它是指向常量值的指针。或者一堆常量值。或者 none。看看指针在哪里?真的很难知道你在做什么是否合适。这是某人的地址,好吧 - 也许吧。它可能没有地址,也可能是挤满整个学校实地考察学生的旅馆的地址,或者可能是一个空的 phone 摊位的地址。你不相信我?这里:
double phoneBooth = std::nan("empty");
double *i_hope_my_friends_are_there = &phoneBooth;
这是真正的 C++。它编译。这和我说的差不多。如果您需要表示一个空的 phone 展位,而您得到的只是一个双人展位,它会在紧要关头完成。您可能希望将其放入一些演示代码中以增加效果。所以,现在你明白为什么指针会很糟糕了。和双打。双打当然很糟糕,但花车更糟糕。哦 - 除非你是大型机程序员。那么这应该是非常熟悉的:
float pbth = nan("MPT");
也是真正的 C++ 代码,除了有人把 using namespace std
放在更早的地方。对于任何熟悉 COBOL 的人来说,这已经足够罗嗦了。 pbth
的定义与 COBOL 背景形成鲜明对比。散发着 System 360 组装的味道。
但是我们越来越分心了。回到range_
!没有人说拥有 range_
属性 的人会用它做什么。他们可能会炸毁整个地方。你所知道的是 你 被禁止更改 属性 上的任何内容 - 如果你得到的只是那个地址簿。所以 - 也许你确实知道你也确实拥有那块土地,然后你就可以成为炸毁它的人。但是很难判断您是否只有那个地址簿。它只是说:
- 你可以来看看这些雕塑,哦 - 顺便说一下 - 展览会在一天中随机变化,但前提是你不断购买西红柿。 (我保证很快就会有 1% 的意义)
现在稍等一下:为什么给定一个地址簿,您会想到两个维度,只是因为您获得地址的东西本身就有一个维度?你根本不需要那样想。至少(数学家除外),任何人都不会自然而然地想到它。如果您对实际上具有二维(空间、矢量-space-ish 或类似的东西)的问题建模,您只会想那样想。否则,就没有什么“2D”的了。您几乎不会认为矩阵是 "two dimensional" 对象。
如果你有一个真实的地址簿,上面写着你朋友的地址,并且到处说你的地址簿是 4D 的,因为它是一个大概是 3D 的“1D”邮政地址列表 space,人们可能对整件事看起来很滑稽。这不是一个非常实用的观点。除了:它只有在帮助您处理问题时才实用。但不应该仅仅因为其他一些人似乎受到了帮助就认为它对你有帮助是理所当然的。希望这一段的警告中的讽刺意味终于暴露无遗。
实际上,如果您有一个具有离散区域单位 ("squares") 的矩形区域,您会认为它具有二维,但通常最紧凑的存储方式不是分块将其分解成更小的碎片,将它们随风飘荡,查看它们落在附近的哪个位置,并收集它们所在的地址。不幸的是,这就是学生,通常是他们倒霉的教授,期望使用一系列指针的方式。相反,只要得到一个足够大的长块,并保留它的地址。或者甚至更好,将它围起来,种一些西红柿,然后按照您想要的顺序收集它们,让方法处理细节。
现在你的需求可能比这个更花哨,但是只要矩形区域是"small",说比浮动少一百个项目,把它全部放在一个块中并移动元素around 可能是最快的处理方式。我的意思是:如果你关心实际性能,而不是一些数学家关于计算机的影子在执行这样的任务时应该如何表现的想法。很少有广泛使用的实用计算机能够达到这样的理念。
就复杂性理论而言,基于 AVR 的 Arduino 有一些非常明确的影子,您可能会发现链表的行为有点像您在算法课程中学到的东西。但是 运行 在您的 PC 上使用相同的程序,稍微调整一下,您就会遇到极端情况,在这种情况下它的性能可能比在 Arduino 上差。我没骗你——这肯定是一个病态的案例,但它并不难编造。词汇量比我高明得多的人称之为 "a denial of service",但我不确定向人们扔西红柿在多大程度上是不让他们吃饭,而不是说给他们喂西红柿。
然后你重写所述程序,使其在 Arduino 上慢 10 倍,但在 PC 上快数千倍。我绝对不是在开玩笑。
从你的问题回到那个破烂的地址簿:它不是很有用,因为它只有一页,大声喊叫。而且没有办法改变这一点。单页,精装,就是你所拥有的。需要存储更多地址?去拿另一个。您还不如只存储一个地址,而无需存储整个地址簿的繁琐内容。一张纸 - 无需装订工作。它可以是单个地址,而不是具有单个元素的数组。像这样:
const float *range = range_;
但是您当然是在编写 C++。而这一切都是愚蠢的。如果您只需要一块可以轻松调整大小的土地,请使用矢量:
struct MyClass {
std::vector<float> range;
};
它在一个结构中,而不是在 class 中,只是因为它告诉了人类一些东西——对编译器来说,这两者实际上是一回事。它告诉人类的是:这里是 属性。没有监督。你明白了,敞开心扉,你做你想做的。有一台挖掘机,想把这个地方挖出来?往前走。除非它是一个 const struct - 否则它是被禁止的。当然。但不总是。如果对象本身是 const 则禁止。但是如果对象不是 const,但你有一个指向它的指针标记为 "pointer to const",你就有了后门。 const_cast
,开动挖掘机,出发。没关系。不是UB
通常我们保留关键字 class
用于以某种方式管理 属性 的用途。土地会在篱笆后面,一群站在篱笆上的人会卖给你土地上生长的西红柿。如果您当着他们的面称呼他们 methods,他们可能会被冒犯,但在软件工程人员中,这样的谈话是司空见惯的。贬低软件工程的东西。
但是假设您确实想要一个向量的向量:
using A_vector_of_vectors = std::vector<std::vector<float>>;
你拥有城市街区,每个街区都有许多房产。与城市街区一样,这只有在街区有些分离而不是交织在一起并且有些独立的情况下才有意义:它们真正以(或不)自己的速度增长,并且它们的规模需求各不相同。如果你想要总是一起访问的街区,并且它们的大小有一些规则模式(全部相等,或者按算术或几何级数 - 类似的东西),你可能只想要一个大城市街区 - 只划定细分在某种地图上,而不是通过道路工程和绕行等方式进行描绘。
您可以拥有零个或多个城市街区:这是外向量。每个城市街区都可以有任意大小——甚至是零大小。当它的大小为零(为空)时,您所得到的只是一个 "name" - 用来调用它的东西,以便您稍后可以说 "hey, we want the Nomish Quarters sized to fit four nomes, please!"。那就是将一个特定的内部向量增加到 4 的大小。
我们可以用简单的符号表示那些向量和子向量的特定内容。假设有三个向量,第一个没有元素,第二个有一个元素,第三个有两个元素。你会这样写下来:{{}, {50}, {80, 90}}
。很容易。现在我们可以使用它来预填充向量的向量:
struct MyClass {
A_vector_of_vectors vov{{}, {50}, {80, 90}};
};
这是制作MyClass
的秘诀:目前这只是一个柏拉图式的想法。有点像素食炸肉排的食谱,上面装饰着完美无暇的图片。当你第一次制作它们时,它们就很适合做鞋底。不过,随后他们往往很棒。是的,class 不存在,只是一个影子。如果你真的想吃一个,你必须创建一个它的实例:
MyClass anInstance;
现在我们得到了一个小城市,有一组三个城市街区,第一个 0 英亩,第二个 1 英亩,第三个 2 英亩。他们非常乐于助人。您可以调整每一个的大小。您可以重新排列它们的顺序,或其中英亩的顺序。您可以添加新的。删除旧的。最好的事情是什么?你让别人做所有的工作。 std::vector
和编译器会处理细节。当您不再需要 anInstance
时,您只需核对它即可。你结束了范围,所以结束了城市。就这样。
int main() {
MyClass anInstance;
} // bye bye, city
你看,没有 malloc
,没有 free
。番茄人为我们做了这一切!
What is range_ doing tho?
float range_[] = {0, 180};
range_
是两个浮点数的数组。第一个值为 0,另一个值为 180。
const float* range[] = {range_};
range
是一个指向 const float 的指针的数组。它指向 range_
.
but idk what it's doing
他们什么都不做。它们是数组。它们包含值。
I'm trying to consolidate them into a class, and C++ is finicky about putting variable length arrays in classes
您显示的数组不是可变长度的。一个的大小为 2,另一个的大小为 1。
如果你想使数组成为成员变量,那么你只需在类型中明确指定该大小,而不是从初始化程序中推导。例如:
struct example {
float range_[2];
const float* range[1];
};
也就是说,据我所知,range
数组似乎没什么用。