字符串方法崩溃程序

时间:2010-06-18 16:36:17

标签: c++ class

好吧所以我有两个相同的字符串方法......

string CreateCust() { 
    string nameArray[] ={"Tom","Timo","Sally","Kelly","Bob","Thomas","Samantha","Maria"};
    int d = rand() % (8 - 1 + 1) + 1;   
    string e =  nameArray[d];
    return e;
   }      

string CreateFood()  {
     string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
     int d = rand() % (3 - 1 + 1) + 1;   
     string f =  nameArray[d];
     return f;
} 

然而无论我做什么,CreateFood的胆量都会崩溃。我为它创建了一个测试机箱,它始终在cMeal = CreateFood();

处失败
        Customer Cnow;        
        cout << "test1" << endl;
        cMeal = Cnow.CreateFood();
        cout << "test1" << endl;
        cCustomer = Cnow.CreateCust();
        cout << "test1" << endl;

我甚至用CreateFood切换CreateCust,它仍然在CreateFood函数...

失败

注意:如果我使createFood成为一个int方法,它确实有用......

即使我改变了CreateFood来改变消息,也没有更多它仍然崩溃......

6 个答案:

答案 0 :(得分:8)

取出两个+ 1,从0开始访问数组:

int d = rand() % (8 - 1 + 1);  // 0-7, not 1-8
int d = rand() % (3 - 1 + 1);  // 0-2, not 1-3

否则您正在访问不存在的元素,这是未定义的行为。 (这意味着它似乎可以正常工作,就像CreateCust一样,像CreateFood一样崩溃,什么也不做,或做任何事情。)


我不确定减去1然后加1的目的是什么。无论如何,现在是学习的最佳时机:不要重复自己。即使你只做了两次,也可以用它来制作一个功能,它就会变得更加神秘,更简洁:

int random(int min, int max)
{
    return rand() % ((b - a) + 1) + a;
}

这是一个简单的函数,可以在ab之间返回一个随机数。 (表示结果中包含ab。)现在您的代码为:

// I'll leave CreateCust up to you

string CreateFood(void)
{
     string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};

     int d = random(0, 2); // either 0, 1, or 2, randomly   
     string f =  nameArray[d];
     return f;
} 

你甚至可以看到只有一个功能让它更容易阅读;您的目标是让您的代码易于被人类阅读。此外,这更简洁:

string CreateFood(void)
{
     string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};

     return nameArray[random(0, 2)];
} 

另一个不好的事情是将魔术数字硬编码到你的程序中。例如,为什么3或8?它可以推导那些是数组大小,但这并不是独立的。你可能想要的是:

string CreateFood(void)
{
     const size_t ArraySize = 3; // 3 elements, 0-2
     string nameArray[ArraySize] = {"spagetti", "ChickenSoup", "Menudo"};
                    // ^ Ensure it matches

     return nameArray[random(0, ArraySize - 1)];
} 

现在,号码的范围很有意义。


剩下的可能有点高级(在你进入模板之前你不会理解),但是展示了我们如何继续:

template <typename T, size_t N>
char (&countof_detail(T (&)[N]))[N];

#define countof(pX) sizeof(countof_detail(pX))

这个漂亮的工具将为您提供数组中元素的数量。代码可能会变成这个

string CreateFood(void)
{
     string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
                    // ^ no explicit size

     return nameArray[random(0, countof(nameArray) - 1)];
} 

我们完全摆脱了任何数字,你可以随意操纵阵列。最后,我们再次重复:从数组中获取一个随机元素。我们应该为此做一个功能:

template <typename T, size_t N>
T& random_element(T (&pArray)[N])
{
    return pArray[random(0, N - 1)];
}

这会从任何数组中返回一个随机元素。那么你的功能就是:

string CreateFood(void)
{
     string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};

     return random_element(nameArray);
} 

请注意,在这个重构中(重构是将代码并将其分解为新的,更简单的部分),它读得更好:为了获得食物,我们有一系列食物,我们随机选择一个。

在工作时记住这些东西,当你学习C ++时,你可以制作更好的代码。任何时候你重复一个不重要的任务,使它成为一个功能。突然之间,这个任务是微不足道的,因为你不关心函数是如何工作的(在函数中),只是关于函数的作用(这是函数名)。

答案 1 :(得分:5)

崩溃正在发生,因为您正在访问无效索引。这是因为数组索引从0而不是1开始,因此您不希望在模数运算符的右值上添加1。

这是一个巧妙的技巧,您可以使用它来使您的代码更易于维护:

template <class T>
T getRandElem( const T[] arr )
{
    return arr[ rand() % ( sizeof(arr) / sizeof((arr)[0]) ) ];
}

string CreateCust(){ 
    static string nameArray[] = {"Tom","Timo","Sally","Kelly","Bob","Thomas","Samantha","Maria"};
    return getRandElem<string>( nameArray ); 
}

string CreateFood(){
     static string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
     return getRandElem<string>( nameArray );
} 

答案 2 :(得分:2)

看这里:

int d = rand() % (8 - 1 + 1) + 1;   

这将返回1到8 包含之间的数字。你需要的是:

int d = rand() % 8;

答案 3 :(得分:1)

你超出了数组的范围。数组对象从0开始。

答案 4 :(得分:0)

我不明白为什么你有

int d = rand() % (8 - 1 + 1) + 1;    

为什么不使用

int d = rand() % 8;

答案 5 :(得分:0)

我认为现代c ++编译器仍然允许你使用旧的C技巧来实现静态数组:

string CreateFood()
{
     char* nameArray = {"spagetti", "ChickenSoup", "Menudo"};
     // note the trick to get the compiler to count the array elements for you:
     int d = rand() % (sizeof(nameArray) / sizeof(nameArray[0]));   
     return std::string( nameArray[d] );
}