Генерация случайного числа в пределах интервала, кроме некоторых чисел: EXC_BAD_ACCESS - PullRequest
0 голосов
/ 13 марта 2012

Я использую xcode 4 на Mac Os X Snow Leopard.Я пытаюсь написать функцию для генерации случайного числа в пределах интервала, за исключением некоторых чисел.
т.е.:

int num=5;
random(time(NULL),1,100,&num,NULL);

Это должно сгенерировать число в пределах 1 и 100, кроме 5. Итак, я 'Вы написали этот код:

//
//  main.cpp
//  CPPTest
//
//  Created by Ramy Al Zuhouri on 3/7/12.
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

#include <iostream>
#include <exception>
#include <cstdarg>
#include <cstdlib>
#include <ctime>

using namespace std;

class cannotGenerate : public exception
{
    virtual const char* what()
    {
        return "Cannot generate any number, maybe the interval is empty, or the exluding vector is too large\n";
    }
};

// Random number generation
// min : min number (included)
// max : max number (included)
// seed : generator seed
// excp1 first argument of int pointers (the last must be NULL)
// the int pointers represent the numbers that must be excluded
// so that if such number is generated, it has to be generated again

int random(unsigned int seed=(unsigned int)time(NULL),int min=0,int max=RAND_MAX, int* excp1=NULL , ...)
{
    // variables

    int result,*ptr;
    va_list vl;
    static unsigned int count=0;

    // instructions

    srand(seed+count++);
    va_start(vl,excp1);
    do   // this do-while has the purpose to keep generating numbers until the number is correct
    {    // correct = within the [min,max] interval and not a number of the list of pointers
        result=rand()%(max-min+1)+min;
        ptr=excp1;
        do  // this do-while has the purpose to check all the va_list and to read all arguments   
        {   // passed to the function
            if(ptr!=NULL)
            {                     // here there is the exception (with gdb 6.3.50) :
                if(result==*ptr)  // Thread 1: Program received signal: "EXC_BAD_ACCESS". 
                    result=min-1;
                ptr=va_arg(vl,int*);
            }
            else
            {
                break;
            }
        }while(ptr!=NULL && (result<min || result>min));
    }while(result<min || result>max);
    va_end(vl);

    // result

    return result;
}

int main (int argc, const char * argv[])
{
    int excp[]={1,2,3,4};
    int rand;
    for(int i=0;i<100;i++)
    {
        rand=random((unsigned int)time(NULL),1,100,&excp[0],&excp[1],&excp[2],&excp[3],NULL);
        if(rand==1 || rand==2 || rand==3 || rand==4)
        {
            cerr << "error" << endl;
            break;
        }
        else
        {
            printf("%d\n",rand);
        }
    }
    return 0;
}

Но с GDB я получаю это исключение:
Поток 1: Программа получила сигнал: "EXC_BAD_ACCESS".
В этом блоке ptr не может быть NULLпоэтому я не могу выяснить причину этого исключения.

Ответы [ 2 ]

1 голос
/ 13 марта 2012

Проблема в том, что вы не сбрасываете список аргументов переменных после первого прогона, поэтому он в конечном итоге указывает на память после ввода NULL, что приводит к исключению (если вам повезет).

Попробуйте заменить случайный внутренний цикл следующим (обратите внимание на размещение va_start и va_end).

 do {
        result=rand()%(max-min+1)+min;
        va_start(vl,excp1);           //note
        ptr=excp1;

        do 
        {
            if(ptr!=NULL)
            {
                if(result==*ptr)
                    result=min-1;
                ptr=va_arg(vl,int*);
            }
            else
            {
                break;
            }
        } while(ptr!=NULL && (result<min || result>min));

        va_end(vl); //note
    }while(result<min || result>max);
1 голос
/ 13 марта 2012

Это много кода.Попробуйте вместо этого:

int z = ((arc4random() % 100)+1);
if (z == 5){
   [self tryAgain]
}else {
  return z;
}

(замените 100 на максимум и 5 на любое количество исключенных переменных)

Будет сгенерировано случайное число от 0 до 99, затем добавьте одно кЭто.Если результат пять, зациклите его, чтобы получить другое число.Также обратите внимание на эту строку в вашем коде:

}while(ptr!=NULL && (result<min || result>min));

Это правильно?меньше или больше минимума?

...