C++ 指针和数组
Posted
技术标签:
【中文标题】C++ 指针和数组【英文标题】:C++ Pointers & Arrays 【发布时间】:2010-11-27 17:17:18 【问题描述】:以下是来自 C++ 过程的一些代码。原件可以在这里找到; https://code.ros.org/trac/opencv/browser/trunk/opencv/modules/imgproc/src/grabcut.cpp
我的观点是我是一个 C# 而不是 C++ 程序员,所以这个代码对我来说有点神秘,即使我通过一个代码转换器运行它并且它没有改变。
我的问题是:a)。 'coefs' 如何成为一个数组,以及 b)。 'c' 是如何填充的?
提供更多信息:'coefs' 开始时似乎不是一个数组,而 'c' 似乎神奇地获得了至少 8 个项目
// fields in class called MAT:
// a distance between successive rows in bytes; includes the gap if any
size_t step;
// pointer to the data
uchar* data;
// where ptr comes from:
template<typename _Tp> _Tp* ptr(int y=0);
template<typename _Tp> inline _Tp* Mat::ptr(int y)
CV_DbgAssert( (unsigned)y < (unsigned)rows );
return (_Tp*)(data + step*y);
.....
// original question code:
static const int componentsCount = 5;
Mat model;
float* coefs;
float* mean;
float* cov;
coefs = model.ptr<float>(0);
mean = coefs + componentsCount;
cov = mean + 3*componentsCount;
for( int ci = 0; ci < componentsCount; ci++ )
if( coefs[ci] > 0 )
calcInverseCovAndDeterm( ci );
void GMM::calcInverseCovAndDeterm( int ci )
if( coefs[ci] > 0 )
float *c = cov + 9*ci;
float dtrm =
covDeterms[ci] = c[0]*(c[4]*c[8]-c[5]*c[7]) - c[1]*(c[3]*c[8]-c[5]*c[6]) + c[2]*(c[3]*c[7]-c[4]*c[6]);
【问题讨论】:
【参考方案1】:当你像这样声明一个数组时:
int my_ints[10];
my_ints
是一个数组。但在 C++ 中,my_ints
也可以作为指向数组中第一项的指针来计算。所以代码如下:
int* the_first_int = my_ints;
...是合法有效的,更不用说很常见了。您也可以像使用数组一样使用the_first_int
,如下所示:
int the_third_int = the_first_int[2];
...这使得在 C 样式数组和指针之间来回切换几乎无缝。
在您的代码中,您声明了一个指向 float
的指针:
float* coefs;
(顺便说一句,这应该初始化为NULLL,但那是另一回事了),然后将其设置为某个值:
coefs = model.ptr<float>(0);
我不知道model.ptr<float>(0)
做了什么,但它可能要么分配一个数组并返回一个指向该数组的指针,要么返回一个指向已经设置好的数组的指针。
现在因为coefs
是指向float
的指针,所以您可以像使用数组一样使用它,您可以在循环中这样做:
for( int ci = 0; ci < componentsCount; ci++ )
if( coefs[ci] > 0 )
这就是它起作用的原因。
【讨论】:
【参考方案2】:
coefs
如何变成数组
在 C 和 C++ 中,p[i]
只是 *(p + i)
的语法糖。当然,这个结构只有在p
恰好指向一个数组的元素并且p + i
没有超出该数组的边界时才有意义。否则,你会得到undefined behavior。
Kos 写道:请不要在每次出现问题时都说“未定义的行为”,除非你可以用标准来支持它
好的,既然你要求它:
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有类型 的指针操作数。如果指针操作数指向数组对象的一个元素,并且数组是 足够大,结果指向与原始元素偏移的元素,使得 结果和原始数组元素的下标等于整数表达式。换句话说,如果 表达式
P
指向数组对象的第i 个元素,表达式(P)+N
(等效于N+(P)
) 和(P)-N
(其中N
的值为n)分别指向数组的第i + n 个和第i 个元素 对象,只要它们存在。此外,如果表达式P
指向数组对象的最后一个元素, 表达式(P)+1
指向数组对象的最后一个元素,如果表达式Q
指向 在数组对象的最后一个元素之后,表达式(Q)-1
指向数组的最后一个元素 目的。 如果指针操作数和结果都指向同一个数组对象的元素,或者一个过去 数组对象的最后一个元素,评估不应产生溢出; 否则,行为未定义。
【讨论】:
不真实...好吧,技术上正确,但不清楚:),因为p
实际上可能指向数组的任何元素。另外,请不要每次出现问题时都说“未定义的行为”,除非您可以用标准来支持它 - 仍然存在“未指定”和“实现定义”,后者基本上意味着存在情况(特定机器,架构,编译器...)这样的代码将是有效的。
@Kos:我明白你的观点,我并不反对,但这实际上是未定义的行为。
@Fred:说“是 p 恰好指向数组中的第一个元素,[否则它是 UB]”不太正确。正确的说法是“如果 *(p+1) 不指向数组中的元素,则得到 ub”是正确的。如果你要祈求UB之神,你应该是正确和准确的。
你是说 - 假设我在 GCC 的 32 位机器上有 3 个 32 位浮点数的 POD 结构 - 如果我尝试通过指向第一个浮点数的指针来引用第二个浮点数增加 1 ,我可以期待恶魔从我的鼻子里飞出来,或者 - 嗯 - 比人们指责我的坏作风更糟糕的事情吗?虽然我无法确认,但我相信这种情况下的行为是可以预测的;这就是我对“实现定义”的理解(类似于工会、reinterpret_casts 等的情况)。如果我在这里错了,请用一些来源纠正我。
@Kos:事物可以由实现定义,而不是实现定义。 C++ 标准将很多东西保留为 UB(这意味着它不是实现定义的),但是没有规则阻止特定实现定义它在该特定实现上的行为方式(所以它是可以预测的,但 C++ 标准并不要求它是这样,因此它仍然是 UB)。如果标准说它是由实现定义的,那么事情只有在 C++ 用语中是实现定义的。这有意义吗?【参考方案3】:
在 C 和 C++ 中,指针和数组是等价的。您可以将它们视为指针或数组,这取决于您。指向单个变量的指针可以被认为是一个包含 1 个元素的数组。
【讨论】:
不,指针和数组不等价。在某些情况下,数组的行为很像指针(数组到指针衰减),但它不是指针。例如,sizeof(some_array)
产生整个数组的大小,而sizeof(some_pointer)
产生指针的大小。
float*
和 float[1]
是存储不同内容的不同类型。
@FredOverflow:它们是等价的,但它们并不相同。 int 和 short 是等价的,但不一样。
int
和 short
到底是如何等效的?
“数组对象可以隐式转换为指向数组内部类型的指针”,用 C++ 术语表示。我不记得 C++ 有 “等效” 的概念。【参考方案4】:
从您的代码看来,model
是实际包含数组的数据结构。
coefs = model.ptr<float>(0);
这里,coefs
不会“变成”数组,而是指向model
中的现有数组,之后它可以像真正的数组一样使用。其他变量mean
、cov
和c
也是如此——它们都被分配了一个指向数组中特定位置的指针。例如:
mean = coefs + componentsCount;
使mean
指向coefs
“数组”的第6 个(从componentsCount = 5
开始)元素。在此之后,mean
可以被视为从model
的第 6 个元素开始的数组。
【讨论】:
【参考方案5】:float *c = cov + 9*ci;
c 是指向 cov 指向的任何位置的指针,加上浮点大小的 9 倍(假设标准 IEEE-754 float
为 4 个字节)。这是指针算法。
我不确定 coefs 指向什么,但我认为它是在 model.ptr<float>(0);
语句中的某个位置分配的。否则,它是一个无效的指针(可能为 NULL)。
在 C 和 C++ 中,存在指针和数组之间的区别的细分。考虑以下代码:
int A[5];
int y = *A; // The first occurrence of A is also the dereferenced value of *A
int z = A[0]; // The first occurrence of A
int *w = A; // pointer to the beginning of A
if (*w == y) // TRUE, dereferenced int value == int value
if (w == A) // TRUE, address == address
【讨论】:
如果 c 是指向 cov 指向的任何位置的指针加上浮点大小的 9 倍(或者您的意思是 int?),我将如何编写想要将 ci 的实际值乘以的代码9 而不是它的字节大小?以上是关于C++ 指针和数组的主要内容,如果未能解决你的问题,请参考以下文章