我想在前面加上我是一个初级但相对有经验的开发人员,但C++经验很少。
我有这个测试方法,它应该传递一个字符数组来找到"O"。
TEST(MyTest, ReturnIndexOfO)
{
Widget unitUnderTest;
char x = 'X';
char o = 'O';
char *row[4] = {&o, &x, &x, &x};
char *row2[4] = {&x, &o, &x, &x};
EXPECT_EQ(unitUnderTest.findEmptySpace(*row, 4), 0);
EXPECT_EQ(unitUnderTest.findEmptySpace(*row2,4 ), 1);
}
这已经正确地调用了我的 findEmptySpace 方法,它是:
#define WHITE_SPACE 'O'
int Widget::findEmptySpace(char row[], int size)
{
cout << "The row under test is:n";
for(int i = 0; i < size; i++) {
cout << row[i];
}
cout << "n";
for(int i = 0; i < size; i++) {
if(row[i] == WHITE_SPACE) {
return i;
}
}
return -1;
}
但不幸的是,我的输出似乎表明并非所有字符都被我的 findEmptySpace 方法读取:
受测行为:
牛
受测行为:
十
因此,即使使用截断的数据,我的第一个测试用例也通过了,但第二个测试用例失败了。知道为什么我没有正确查看数据吗?
此表达式
Test.findEmptySpace(*row, 4)
等效于表达式
Test.findEmptySpace(row[0], 4)
元素row[0]
是一个指针,其值&o
指向类型为char
的标量对象o
char o = 'O';.
因此,具有此类参数的函数调用(函数中的内部循环)没有意义
似乎你的意思是以下内容
EXPECT_EQ(unitUnderTest.findEmptySpace(row, 4), 0);
和
#define WHITE_SPACE 'O'
int Widget::findEmptySpace(char * row[], int size)
{
cout << "The row under test is:n";
for(int i = 0; i < size; i++) {
cout << *row[i];
}
cout << "n";
for(int i = 0; i < size; i++) {
if( *row[i] == WHITE_SPACE) {
return i;
}
}
return -1;
}
当你打电话时
unitUnderTest.findEmptySpace(*row, 4)
表达式row
将衰减到指向row
的第一个元素的指针,即指向&row[0]
的指针。因此表达式*row
等价于row[0]
,它是指向变量o
的指针,即指向单个字符的指针。
在函数Widget::findEmptySpace
中,在下面的循环中,您可以使用指向单个字符的指针,就好像它是指向 4 个字符的指针一样:
for(int i = 0; i < size; i++) {
cout << row[i];
}
由于函数参数row
(与具有该名称的原始数组相反)是指向单个字符的指针,因此row
的唯一有效索引将是row[0]
。但是,您正在使用索引row[0]
row[3]
,因此您正在越界访问对象,从而导致未定义的行为。
函数签名
int Widget::findEmptySpace(char row[], int size)
可能不是你想要的。如果要将指向整个数组的指针row
从函子传递到函数TEST
findEmptySpace
,那么您应该传递指向数组第一个元素及其长度的指针。你已经正确地做了后者,但你没有正确地做前者。因为数组的每个元素都是char *
类型,指向数组第一个元素的指针将是char **
类型,即指向指针的指针。因此,应将函数签名更改为以下内容:
int Widget::findEmptySpace( char **row, int size )
或者,如果您愿意,可以使用此等效项来明确表示更高级别的指针指向数组:
int Widget::findEmptySpace( char *row[], int size )
当然,您必须重写函数findEmptySpace
以适应不同的参数类型,以便它取消引用指针:
int Widget::findEmptySpace( char *row[], int size )
{
cout << "The row under test is:n";
for( int i = 0; i < size; i++ ) {
cout << *row[i];
}
cout << "n";
for( int i = 0; i < size; i++ ) {
if( *row[i] == WHITE_SPACE ) {
return i;
}
}
return -1;
}
现在,在函数TEST
中,由于更改了函数参数,您必须更改调用函数findEmptySpace
的方式。您应该更改行
EXPECT_EQ(unitUnderTest.findEmptySpace(*row, 4), 0);
EXPECT_EQ(unitUnderTest.findEmptySpace(*row2,4 ), 1);
自:
EXPECT_EQ(unitUnderTest.findEmptySpace( row, 4), 0);
EXPECT_EQ(unitUnderTest.findEmptySpace( row2, 4 ), 1);
现在,您不再传递第一个数组元素的值,而是传递指向第一个数组元素的指针,以便函数findEmptySpace
可以正确访问整个数组。
char *row[4] = {&o, &x, &x, &x};
这不是"字符数组"。这是一个由四个指向字符的指针组成的数组。
unitUnderTest.findEmptySpace(*row, 4)
这会将这些指针中的第一个传递到findEmptySpace()
其第一个参数中。第一个指针是指向o
的指针。
要findEmptySpace()
的第二个参数是 4。这就是上述声明在C++中所做的。
该函数findEmptySpace()
执行以下操作:
for(int i = 0; i < size; i++) {
cout << row[i];
}
因此,它最终会打印传递给它的指针中的前四个字符。
问题是传入的指针是指向一个字符的指针:
&o
这是第一个指针。此函数最终尝试从仅指向一个字符的指针读取前四个字符。
这会导致未定义的行为。