字符串方法崩溃程序

Tim*_*ech -1 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;
} 
Run Code Online (Sandbox Code Playgroud)

然而无论我做什么,CreateFood的胆量总会崩溃.我为它创建了一个测试机箱,它总是失败cMeal = CreateFood();

        Customer Cnow;        
        cout << "test1" << endl;
        cMeal = Cnow.CreateFood();
        cout << "test1" << endl;
        cCustomer = Cnow.CreateCust();
        cout << "test1" << endl;
Run Code Online (Sandbox Code Playgroud)

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

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

即使我改变CreateFood只是COUT一条消息,也没有更多它仍然崩溃...

GMa*_*ckG 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
Run Code Online (Sandbox Code Playgroud)

否则,您正在访问不存在的元素,这是未定义的行为.(这意味着它似乎可以起作用,比如在CreateCust崩溃中CreateFood,什么也不做,或做任何事情.)


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

int random(int min, int max)
{
    return rand() % ((b - a) + 1) + a;
}
Run Code Online (Sandbox Code Playgroud)

这是一个简单的函数,它返回一个a和之间的随机数b.(意味着它可以包括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;
} 
Run Code Online (Sandbox Code Playgroud)

而且你会发现即使只有一个功能也可以让它更容易阅读; 您的目标是让您的代码易于被人类阅读.此外,这更简洁:

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

     return nameArray[random(0, 2)];
} 
Run Code Online (Sandbox Code Playgroud)

另一个不好的事情是将魔术数字硬编码到你的程序中.例如,为什么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)];
} 
Run Code Online (Sandbox Code Playgroud)

现在,数字的范围很有意义.


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

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

#define countof(pX) sizeof(countof_detail(pX))
Run Code Online (Sandbox Code Playgroud)

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

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

     return nameArray[random(0, countof(nameArray) - 1)];
} 
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

     return random_element(nameArray);
} 
Run Code Online (Sandbox Code Playgroud)

请注意这个重构(重构是将代码和因子分解成新的,更简单的部分),它读得更好:为了获得食物,我们有一系列食物,我们随机挑选一个.

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


B J*_*son 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 );
} 
Run Code Online (Sandbox Code Playgroud)