Выбрать главу

int ind = 0; /* индекс массива */

while((ch = getchar( )) = = '\n' || ch == '  ' || ch == '\t');

/* обход начальных символов "новая строка", пробелов и табуляций */

while(ch != EOF && ch != '\n' && ch != '   ' && ind < LEM)

{

intarr[ind++] = ch; /* запись символа в массив */

ch = getchar( ); /* получение очередного символа */

}

intarr[ind] = '\0'; /* конец массива по нуль-символу */

if(ch == EOF)

return(STOP);

else                                                            

return(stoi(intarr, ptint) ); /* выполнение преобразования */

}

РИС. 10.3. Программа функции getint( )

     Мы получаем символ сh. Если он является символом пробела, или "новой строки", или табуляции, мы берем следующий символ и так продолжаем до тех пор, пока не получим символ, отличающийся от перечисленных. Затем, если этот символ не EOF, помещаем его в массив. Продолжаем брать символы и помещать их в массив, пока не найдем запрещенный символ или не достигнем предельного размера строки. Далее помещаем нуль-символ (' \0') в следующую позицию массива, чтобы отметить конец строки. Таким образом, мы создали массив в виде стандартной символьной строки. Если EOF был последним прочитанным символом, возвращаем STOP; иначе идем дальше и пытаемся преобразовать строку. Мы вызываем новую функцию stoi( ), чтобы выполнить эту работу. Что делает stoi( )? При вводе она берет символьную строку и указатель на целую переменную, использует указатель для присваивания значения самой переменной, а также return для пересылки сообщения о состоянии, которое getint( ) передает затем функции getarray( ). Поразительно! Двойная игра! Вот менее компактный способ использования функции stoi( ):

status = stoi(intarr, print);

return (status);

Здесь status была бы переменной типа int. Первый оператор дает значение, на которое указывает ptint; она также присваивает значение переменной status. Второй оператор возвращает это значение программе, которая вызвала getint( ). Наша единственная строка программы имеет точно такой же эффект, за исключением того, что нам не нужна промежуточная переменная status. Теперь напишем функцию stoi( ).

Преобразование строки в целое: stoi( )

     Сначала опишем, каким должен быть вход и выход у этой функции. Вход будет символьной строкой, поэтому stoi( ) будет иметь символьную строку в качестве аргумента. На выходе должно быть получено два значения: состояние и преобразованное целое число. Мы применяем return для состояния и поэтому должны использовать указатель для возврата другого значения. Таким образом, появится второй аргумент - указатель на целое число. Скелет нашей функции будет выглядеть примерно так:

stoi(string, intptr)

char string[ ];  /* вводимая строка * /

int *intptr; /* указатель на переменную, получающую целое значение*/

{

int status;

...

return(status);

}

Прекрасно, а что можно сказать об алгоритме выполнения преобразования? На некоторое время проигнорируем знак и предположим, что строка содержит только цифры. Возьмем первый символ и преобразуем его в числовой эквивалент. Предположим, это символ '4'. Он имеет в коде ASCII числовое значение 52 и в таком виде запоминается. Если мы из него вычтем 48, то получим 4, т. е.

'4' - 48 = 4

Но 48 - это ASCII-код символа '0', поэтому

'4' - '0' =4

     Действительно, этот последний оператор был бы справедлив в любом коде, в котором используются последовательные числа для представления последовательных цифр. Поэтому если num- числовое значение, a chn- символ цифры, то

num = chn - '0';

Итак, мы используем этот метод для преобразования первой цифры в число. Теперь возьмем следующий элемент массива. Если он '\0', то у нас была только одна цифра, и мы закончили работу. Предположим, однако, что этот элемент '3'. Превратим его в числовое значение 3. Но если оно равно 3, то 4 должно было быть числом 40, а оба числа вместе 43:

num = 10 * num + chn - '0';

     Теперь просто продолжим этот процесс, умножая старое значение num на 10 каждый раз, когда мы находим следующую цифру. Наша функция будет использовать этот метод.

     Вот определение функции stoi( ). Мы храним ее в том же файле, что и getint( ), так что она может использовать те же самые директивы #define.

/* превращает строку в целое число и сообщает о состоянии */

stoi(string, intptr)

char  string[ ];  /* строка, подлежащая преобразованию в целое*/

int *intptr;   /* значение целого */

{

int sign = 1; /* проверяет наличие знака +  или - */

int index = 0;

if(string[index] == '-' ||  string[index] == '+')

sign = (string[index ++] == '-') ? -1 : 1; /* установить знак */

*intptr = 0; /* начальное значение */

while(string[index] >= '0' && string[index] <= '9')

*intptr = 10 * (*intptr) + strmg[index++] - '0';

if(string[index] == '\0')

{

*intptr = sign * (*intptr);

 return(YESNUM); }

else /* найден символ, отличный от цифры, знака или ' \0'  */

return(NONUM);

}

Оператор while продолжает работу, преобразуя цифры в числа, пока не достигнет нецифрового символа. Если это символ'\0', все прекрасно, потому что он означает конец строки. Любой другой нецифровой символ отсылает программу кelse для сообщения об ошибке.

     Стандартная библиотека языка Си содержит функцию atoi( ) (перевод кода ASCII в целое число), очень похожую на stoi( ). Основная разница заключается в том, что stoi( ) проверяет на нецифровые строки, a atoi( ) использует return вместо указателя, для возврата числа, и пропускает пробел, как мы это делали в getint(). Можно было бы осуществить все проверки состояния в getint( ) и использовать atoi( ) вместо stoi( ), но мы полагаем, что было бы интереснее разрабoтать нашу собственную версию.

Проверка

     Так ли уж правильны наши рассуждения? Давайте проверим нашу функцию на учебной программе:

/* проверка функции getint( )*/