#arrays #c #char
#массивы #c #символ
Вопрос:
У меня есть массив символов, где должны быть только числа (10 цифр). Если пользователь вводит буквы или специальные символы (даже среди этих цифр), программа должна снова предложить пользователю ввести число.
Я перепробовал так много способов сделать это, но все равно не смог найти способ. Это то, что я мог сделать до сих пор:
int f = 1;
int i = 0;
int flag =1;
char num[11];
printf("Enter a number: ");
while (f == 1) {
scanf("s", num);
while (flag == 1 amp;amp; isdigit(num[i])) {
i ;
if (i == 10) {
f = 0;
flag =0;
}
}
if (!isdigit(num[i])) {
printf("Enter numerical char: ");
}
}
После того, как я ввожу неверное значение, отображается пустая строка. Если я добавлю какое-либо значение в эту пустую строку, только тогда он скажет «Введите числовой символ:» и предложит снова ввести число.
PS Я знаю, что есть способ гарантировать, что вводятся только числовые значения, учитывая тот факт, что символы, в отличие от чисел, заключены в одинарные кавычки. (понятия не имею, как это сделать tbh)
Заранее спасибо!
Комментарии:
1. Где вы устанавливаете
i
значение 0?2. Я предлагаю преобразовать строку с
strtol()
помощью, чтобы вы могли проверить символ, на котором остановилось преобразование, илиstrtoll()
.3. Я не уверен, что понял ваш вопрос. Я установил i в 0 в самом начале. @stark
4. Итак, что находится
i
на втором числе?
Ответ №1:
Есть несколько способов сделать это.
Простой способ — использовать fgets
для получения строки.
Затем мы можем использовать strtol
для декодирования числа [и мы проверяем конечный символ на достоверность].
Чтобы сделать это полностью вручную, мы можем использовать isdigit
в цикле, наращивая число по одной цифре за раз.
Вот несколько примеров кода с комментариями, которые показывают оба способа:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
// getstr -- get a string with prompt
// RETURNS: length or (<0 -> error)
int
getstr(char *buf,int buflen,const char *prompt)
{
char *cp;
int ret = 0;
// NOTE: usage of the error codes in errno.h is arbitrary
while (ret <= 0) {
// ensure buffer has enough space
if (buflen < 2) {
ret = -ENOMEM;
break;
}
// output prompt
printf("%s: ",prompt);
fflush(stdout);
// get a line
cp = fgets(buf,buflen,stdin);
// EOF
if (cp == NULL) {
ret = -ENODATA;
break;
}
// get buffer length
ret = strlen(buf);
// empty string
if (ret <= 0)
continue;
// point to last char
cp = amp;buf[ret - 1];
// ensure we got a newline -- if not, fgets had to chop the line (i.e.)
// the line is too long to fit in the buffer
if (*cp != 'n') {
ret = -ENOSPC;
break;
}
// strip the newline -- we are done
*cp = 0;
--ret;
}
return ret;
}
// getnum_strtol -- get number using strtol
long
getnum_strtol(const char *prompt)
{
int len;
int readflg = 1;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
if (len < 0)
exit(1);
num = strtol(buf,amp;cp,10);
// ensure we got a least one digit
if (cp <= buf)
continue;
switch (*cp) {
case ' ':
case 't':
case 0:
readflg = 0;
break;
default:
printf("getnum_strtol: not a valid number -- buffer '%s', invalid '%s'n",
buf,cp);
break;
}
}
return num;
}
// getnum_manual -- get number _not_ using strtol
long
getnum_manual(const char *prompt)
{
int len;
int readflg = 1;
int sign = 0;
int valid;
int chr;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
// fatal error
if (len < 0)
exit(1);
// point to buffer start
cp = buf;
// find first non-whitespace character
valid = 0;
while (1) {
chr = *cp;
// end of string
if (chr == 0)
break;
// found character
valid = ((chr != ' ') amp;amp; (chr != 't'));
if (valid)
break;
cp;
}
if (! valid)
continue;
// reset the accumlated number and the sign
num = 0;
sign = 0;
valid = 0;
// loop through all characters in buffer
while (1) {
chr = *cp ;
// get the sign of the number (and skip an explicit sign)
if (sign == 0) {
switch (chr) {
case ' ':
sign = 1;
chr = *cp ;
break;
case '-':
sign = -1;
chr = *cp ;
break;
default:
sign = 1;
break;
}
}
// stop decoding number on whitespace
switch (chr) {
case ' ':
case 't':
chr = 0;
break;
}
// check for clean end of number
if (chr == 0) {
if (valid) {
readflg = 0;
break;
}
}
// not a valid digit
if (! isdigit((unsigned char) chr)) {
cp -= 1;
printf("getnum_manual: not a valid number -- buffer '%s', invalid '%s'n",
buf,cp);
break;
}
// add digit to number
num *= 10;
chr -= '0';
num = chr;
// we got at least one valid digit
valid = 1;
}
}
// apply sign
num *= sign;
return num;
}
int
main(int argc,char **argv)
{
char *cp;
int opt_s = 0;
long num;
// skip over program name
--argc;
argv;
// get options
for (; argc > 0; --argc, argv) {
cp = *argv;
if (*cp != '-')
break;
cp = 2;
switch (cp[-1]) {
case 's': // use strtol
opt_s = ! opt_s;
break;
}
}
while (1) {
if (opt_s)
num = getnum_strtol("Enter number [strtol]");
else
num = getnum_manual("Enter number [manual]");
printf("The number entered is: %ldn",num);
if (num == 999)
break;
}
return 0;
}
Комментарии:
1. Незначительный: «если нет, fgets пришлось вырезать строку (т. Е.) // строка слишком длинная, чтобы поместиться в буфер» или был прочитан какой-то текст (не полный буфер), и
fgets()
результаты отображаются в конце файла.
Ответ №2:
Работа с вводом из stdin
C может быть затруднительной. Я попытался объяснить, что нужно сделать в комментариях, сохраняя ваши переменные в том виде, в котором вы хотели, чтобы они использовались. Но мне нужно было добавить int ch
, чтобы захватить входные данные stdin
. Способ, которым я захватил ввод, ДАЛЕК! из идеального, но он иллюстрирует идею и делает то, что вам нужно. Но, чтобы улучшить ваш ответ, я бы предложил переместить его в собственную функцию. Кроме того, он игнорирует ввод цифр, превышающих 10 символов, поэтому, если, например, вы вводите 012345678901234567, он просто проигнорирует ввод после 10-й цифры, но все равно пройдет тест на ваши переменные и флаги. Комментарии должны быть понятны сами по себе. Я не проверял это, кроме как для того, чтобы убедиться, что он скомпилирован и один раз для цифр и один раз для цифр и текста, но идея есть, и вы должны иметь возможность расширить ее в соответствии с вашими требованиями.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h> /* for fflush */
int main()
{
int f = 1; /* set f on */
int i = 0;
int flag = 0; /* set flag OFF */
char num[11];
int ch; /* adding ch to read characters from stdin */
printf("Enter a number: "); /* flush stdout if no newline */
fflush(stdout);
while(f == 1) {
/* you need to read stdin to the newline */
/* but not exceed the bounds of num */
ch = fgetc(stdin);
while(ch != 'n' amp;amp; ch != EOF) {
if(i < 10) /* reusing your i variable that you set to 0, don't exceed 10 to save space for '' */
num[i] = ch;
i ;
ch = fgetc(stdin); /* get another character */
}
/* now add '' to terminate your string */
/* but not beyond num[10] */
if(i > 10) {
num[10] = '';
} else {
num[i] = '';
}
/* now that we are done reading stdin reset i to 0 to restore how you had it */
i = 0;
/* lets test num working with your variables */
while(num[i] != '' amp;amp; flag == 0) {
/* test for digit at num[i] */
if(!isdigit(num[i]))
flag = 1; /* not a digit so set your flag variable on */
i ;
}
/* process your flag variable */
if(flag == 0) { /* flag is off so everything is ok */
f = 0; /* turn f off to exit loop */
} else { /* flag is on, so get another number */
printf("Enter numerical char: "); /* flush stdout if no newline */
fflush(stdout);
flag = 0; /* turn your flag variable back off */
i = 0; /* reset i to 0 to check the next input */
}
}
/* let's see what we got in num */
printf("%sn", num);
return 0;
}