2013-04-12 3 views
3

Я испытываю очень странную проблему с atoi(char *). Я пытаюсь преобразовать char в его числовое представление (я знаю, что это число), который отлично работает 98.04% времени, но это даст мне случайное значение в другой 1,96% времени.Odd atoi (char *) issue

Вот код, я использую, чтобы проверить:

int increment = 0, repetitions = 10000000; 
for(int i = 0; i < repetitions; i++) 
{ 
    char randomNumber = (char)rand()%10 + 48; 
    int firstAtoi = atoi(&randomNumber); 
    int secondAtoi = atoi(&randomNumber); 
    if(firstAtoi != secondAtoi)NSLog(@"First: %d - Second: %d", firstAtoi, secondAtoi); 
    if(firstAtoi > 9 || firstAtoi < 0) 
    { 
     increment++; 
     NSLog(@"First Atoi: %d", firstAtoi); 
    } 
} 
NSLog(@"Ratio Percentage: %.2f", 100.0f * (float)increment/(float)repetitions); 

Я использую GNU99 C диалектного языка в XCode 4.6.1. Первое, если (когда первое число не равно второму) никогда не регистрируется, поэтому оба atoi возвращают одинаковый результат каждый раз, однако каждый раз результаты разные. «Ошибочные результаты», по-видимому, варьируются от -1000 до 10000. Я не видел ничего выше 9999 или ниже -999.

Пожалуйста, дайте мне знать, что я делаю неправильно.


EDIT:

Я теперь изменил дизайн персонажей, чтобы:

char numberChar = (char)rand()%10 + 48; 
char randomNumber[2]; 
randomNumber[0] = numberChar; 
randomNumber[1] = 0; 

Однако, я использую:

MAX(MIN((int)(myCharacter - '0'), 9), 0) 

, чтобы получить целое значение.

Я очень ценю все ответы!

+0

Почему вы используете 'atoi' в любом случае?у вас уже есть '[NSString intValue]' –

+1

@xlc Это потому, что его немного безумный, чтобы преобразовать 'char' в' NSString', а затем в 'int'. – RileyE

+0

вам не нужно 'atoi' конвертировать char в int. 'char c = '1'; int i = c - '0'; ' –

ответ

6

atoi ожидает строку. Вы не дали ему строку, вы дали ей один char. Строка определяется как некоторое количество символов , заканчивающееся нулевым символом. Вы вызываете UB.

Из документов:

Если ул не указывает на действительный C-строки, или если преобразованное значение будет вне диапазона значений, изображаемых в междунар, это приводит к непредсказуемому поведению ,

Хотите «преобразовать» символ в его интегральное представление? Не перегружайте вещи;

int x = some_char; 

char представляет собой целое число уже, а не строка. Не думайте ни о одном char в качестве текста.

+3

Если символ содержит символ из 0-9, преобразование будет «int x = some_char -« 0 ». Но в противном случае абсолютно правильно, +1 – JustSid

+0

Думаю, мне просто нужно что-то сделать по строкам 'MAX (MIN ((int) myCharacterNumber - 48, 9), 0)'. Я надеялся найти лучшее решение. Кроме того, я не слишком хорошо знаком с тем, как создать c-строку с символом. Я бы просто сделал что-то по строкам 'char cString [] = (char) malloc (sizeof (char) * 2); cString [0] = myCharacterNumber; cString [1] = '\ 0'; '? – RileyE

+1

@RileyE Спасите себя от неприятностей и просто сделайте 'char cString [2];'. Назначьте 'cString [1]' to '0' и' cString [0] 'для значения char. – 2013-04-12 01:46:09

2

Если я не ошибаюсь, atoi ожидает строку с нулевым символом (см. documentation here).

Вы передаете одно значение на основе стека, которое не должно быть завершено нулем. Я очень удивлен, что он даже прав: он может читать сотни единиц мусора в вечность, если он никогда не найдет нуль-терминатор. Если вы просто хотите получить номер одного символа (как, например, числовое значение читаемого человеком символа), почему бы вам просто не сделать int numeric = randomNumber - 48?

+0

'atoi', скорее всего, вернет« действительное »значение, когда видит несимметричный символ. Но 'atoi()' по существу не проверяет ошибок, поэтому его не следует использовать, если вы не * определенно *, что вы передаете ему указатель на действительную строку. –

+0

@KeithThompson Это хорошо знать, что это не сходит с ума. – 2013-04-12 01:45:03

+1

Спасибо, доктор! – RileyE