3

我有一个非常简单的 const char 数组示例和一个应该将它们打印出来的函数(遍历所选的一个)。与我的所有期望相反,它正在遍历所有这些,而不仅仅是作为参数传递的那个。

#include <iostream>

const char* oranges[] = {
    "ORANGE",
    "RED ORANGE"
};

const char* apples[] = {
    "APPLE"
};

const char* lemons[] = {
    "LEMON"
};

void printFruit(const char** fruit){
    int i =0;
    while (fruit[i] != '\0'){
        std::cout << "---------------------\n";
        std::cout << fruit[i] << "\n";
        i++;
    }
}

int main (int argc, const char * argv[])
{
   printFruit(oranges); 
   return 0;
}

我期望的结果是函数 printFruit 以橙子作为参数将打印 ORANGE 和 RED ORANGE,同时我打印了所有定义的水果(来自其他数组),如下所示:

---------------------
ORANGE
---------------------
RED ORANGE
---------------------
APPLE
---------------------
LEMON

对不起我的无知,但为什么会发生这种情况?

编辑:我关注了这个问题:在与我的类似的 c 中定义和迭代字符串数组。

4

5 回答 5

7

你在这里有UB。你的情况

while (fruit[i] != '\0')

永远不会满足,因为没有元素等于\0.

所有的数组都一个接一个地放置在内存中。你的i不断增加永远。i = 1你在第一个字符串上orangesi = 2你在第二个元素上。

之后,i变为 3。因为在 之后oranges,数组中存在apples数组,您的指针开始指向它并且应用程序打印APPLEi = 4指针位于数组上lemons,应用程序打印LEMONS. 在那之后,你有效地走出了你自己的记忆,这对我来说会导致崩溃。

要解决这个问题,您需要在每个数组中显式添加一个空元素,例如

const char* oranges[] = {
    "ORANGE",
    "RED ORANGE",
    0
};
于 2012-10-12T10:16:31.627 回答
5

你正在检查那个fruit[i] != '\0'。这是错误的,因为fruit[i]它是一个char *,而不是一个字符。此外,您的向量不会终止。您可能想检查是否fruit[i] != 0*fruit[i] != '\0'。在第一种情况下,您需要像这样终止向量:

const char* oranges[] = {
    "ORANGE",
    "RED ORANGE",
    0  // or NULL
};

在第二:

const char* oranges[] = {
    "ORANGE",
    "RED ORANGE",
    ""
};
于 2012-10-12T10:15:29.737 回答
2

恕我直言,你最好确切地知道你正在处理多少个元素。坏消息是一个简单的字符指针数组不会告诉你(它不是 a std::vector),所以你将无法在你的printFruit函数中发现它。

然而,好消息是它在编译时可用,因此您不必担心查找它的开销。以下显示了我的意思:

void printFruit(const char** fruit, int fruitSize){
    int i =0;
    while (i < fruitSize){
        std::cout << "---------------------\n";
        std::cout << fruit[i] << "\n";
        i++;
    }
}

int main (int argc, const char * argv[])
{
   // The second parameter can be worked out by the compiler.
   printFruit(oranges, sizeof(oranges)/sizeof(const char*) ); 
   return 0;
}

由于您使用的是 C++,我强烈建议您使用其中一种标准集合类型,例如vector它们在边界检查、内存分配等方面更安全。

于 2012-10-12T10:32:04.793 回答
1
const char* oranges[] = {
    "ORANGE",
    "RED ORANGE"
};

const char* apples[] = {
    "APPLE"
};

const char* lemons[] = {
    "LEMON"
};

在记忆中看起来像

“橙子”“红橙子”“苹果”“柠檬”

while (fruit[i] != '\0'){
    std::cout << "---------------------\n";
    std::cout << fruit[i] << "\n";
    i++;
}

当您到达“大数组”的末尾即“柠檬”时将结束

要使您的代码正常工作,您需要内存看起来像 "ORANGE""RED ORANGE"0"APPLE"0"LEMON"0 所以

   const char* oranges[] = {
        "ORANGE",
        "RED ORANGE",
    0
    };

    const char* apples[] = {
        "APPLE",
    0
    };

    const char* lemons[] = {
        "LEMON"
     ,0
    };
于 2012-10-12T10:18:15.007 回答
0
const char* oranges[] = {
    "ORANGE",
    "RED ORANGE",
    "\0"
};

您的数组一个接一个地位于内存中,因此它会继续打印其他数组,因为while条件是false

于 2012-10-12T10:14:29.743 回答