2017-02-13 4 views
2

Я хочу проверить, чтобы строка, содержащаяся в массиве с именем secretWord, не имела в ней символов (например, $% & #). Если в нем есть символ, я заставляю пользователя повторно вводить строку. Он использует рекурсию, чтобы продолжать просить, пока они не введут строку, которая не содержит символ.Как проверить, содержит ли индекс символ?

Единственный символ I do accept - это символ NULL (символ, обозначаемый значением ASCII нуля). Это потому, что я заполняю все пустое пространство в массиве символами NULL.

Моя функция заключается в следующем:

void checkForSymbols(char *array, int arraysize){ //Checks for symbols in the array and if there are any it recursively calls this function until it gets input without them. 
for (int i = 0; i < arraysize; i++){ 
    if (!isdigit(array[i]) && !isalpha(array[i]) && array[i] != (char) 0){ 
     flushArray(array, arraysize); 
     printf("No symbols are allowed in the word. Please try again: "); 
     fgets(secretWord, sizeof(secretWord) - 1, stdin); 
     checkForSymbols(secretWord, sizeof(secretWord)); 
    }//end if (!isdigit(array[i]) && !isalpha(array[i]) && array[i] != 0) 
    else 
     continue; 
    }//end for(i = 0; i < sizeof(string[]); i++){ 
}//end checkForSymbols 

Проблема: Когда я вхожу любой входной сигнал (смотрите пример ниже), то if заявление работает (он печатает No symbols are allowed in the word. Please try again: и запрашивает новый вход). Я предполагаю, что проблема, очевидно, проистекает из утверждения if (!isdigit(array[i]) && !isalpha(array[i]) && array[i] != (char) 0). Но я попытался изменить часть (char) 0 на '\0' и 0, а также ни одно изменение не произвело никакого эффекта.

Как сравнить, если то, что находится в индексе, является символом, то? Почему строки без символов устанавливают это утверждение if?

И если любой из вас задаются вопросом, что метод «flushArray» Я был, вот он:

void flushArray(char *array, int arraysize){ //Fills in the entire passed array with NULL characters 
    for (int i = 0; i < arraysize; i++){ 
    array[i] = 0; 
    } 
}//end flushArray 

Эта функция вызывается на третьей линии моего основного метода(), сразу после того, оператор печати в первой строке, который просит пользователей ввести слово, и оператор fgets() на второй строке, который получает вход, который используется этой функцией checkForSymbols.


По желанию, примером может быть, если я ввода «Hello» в качестве secretWord строки. Затем программа запускает функцию на нем, и if заявление по какой-то причине срабатывает, заставляя его

  1. Заменить все значения, хранящиеся в secretWord массиве со значением ASCII 0. (AKA NULL)
  2. Распечатывает No symbols are allowed in the word. Please try again: на консоль.
  3. Ждет нового ввода, который он будет хранить в массиве secretWord.
  4. Вызывает метод checkForSymbols() для этих новых значений, хранящихся в secretWord.

И независимо от того, что вы вводите в качестве нового secretWord, в checkForSymbols() метода if заявление костров и повторяет шаги 1 - 4 снова.


Благодарим за терпение и понимание с вашей помощью!

+2

Просьба указать [mcve], в том числе информацию о том, как считывался вход, что такое точный входной тест и как эта функция была вызвана. – kaylum

+1

Вызывается ли flushArray до ввода пользователем в массив? Кроме того, почему бы просто не остановиться, когда вы найдете первый нуль (например, рассматриваете его как строку с завершающим нулем)? – samgak

+1

Кроме того, вы должны научиться использовать отладчик, тогда вы можете увидеть, что это значение в массиве [i], который не прошел тест. Или вы можете просто распечатать его (или это значение ASCII) – samgak

ответ

1

Вы можете сделать что-то вроде этого, чтобы найти символы в коде, поместите код в нужном месте

#include <stdio.h> 
#include <string.h> 
int main() { 
     char invalids[] = "@.<#>"; 
     char * temp; 
     temp=strchr(invalids,'s');//is s an invalid character? 
     if (temp!=NULL) { 
      printf ("Invalid character"); 
     } else { 
      printf("Valid character"); 
     } 
    return 0; 
} 

Это будет проверять, если s действительна запись или нет аналогичен для вы можете создать массив и сделать что-то например, если массив не завершен нулем.

#include <string.h> 
char false[] = { '@', '#', '&', '$', '<' }; // note last element isn't '\0' 
if (memchr(false, 'a', sizeof(false)){ 
     // do stuff 
} 

memchr используется если массив не нулем.

Как было предложено @David C. Rankin вы можете также использовать strpbrk как

#include <stdio.h> 
#include <string.h> 
int main() { 
     const char str1[] = ",*#@_$&+.!"; 
     const char str2[] = "@#"; //input string 
     char *ret; 
     ret = strpbrk(str1, str2); 
     if(ret) { 
      printf("First matching character: %c\n", *ret); 
     } else { 
      printf("Continue"); 
    } 
return(0); 
} 
+0

Да, но это означает, что мне нужен конечный список общих символов, которые я должен был бы напечатать вручную. Я просто хочу обнаружить ** НИЧЕГО **, это не письмо или номер. – Omninano

+0

@ Omninano да тогда отмените логический взгляд на atoz и 0to9 как на ваше ложное состояние. – minigeek

+0

@Omninano попробуйте заменить 'if (! Isdigit (array [i]) &&! Isalpha (array [i]) && array [i]! = (Char) 0)' с 'if (isdigit (array [i]) | | isalpha (array [i]) || array [i] == (char) 0) '& put' checkForSymbols (secretWord, sizeof (secretWord)); 'in else вместо – minigeek

1

Единственный символ я принимаю это символ NULL (символ представлен значением ASCII нуля). Это потому, что я заполняю все пустое пространство в массиве символами NULL.

NULL - указатель; если вы хотите иметь значение символа 0, вы должны использовать 0 или '\0'. Я полагаю, вы используете memset или strncpy, чтобы гарантировать, что конечные байты равны нулю? Нет. Какой позор, ваш MCVE может быть намного короче (и полный). :(


void checkForSymbols(char *array, int arraysize){ 
    /* ... */ 
     if (!isdigit(array[i]) && !isalpha(array[i]) /* ... */ 

В соответствии с разделом 7.4p1 стандарта C, ...

Во всех случаях аргумент является INT, значение которого должно быть представима как символ без знака или будет равен значению макроса EOF. Если аргумент имеет любое другое значение, поведение не определено.

Не все char значения представимы как unsigned char или равно EOF и поэтому возможно (и весьма вероятно, учитывая характер этого вопроса), что приведенный выше код вызывает неопределенное поведение.

Как вы не завершили свой вопрос (путем предоставления MCVE, и описание того, что ошибки встречающиеся) Я предполагаю, что вопрос вы пытается спросить может быть дубликатом this question, this question , this question, this question и, возможно, много других ... Если да, то вы попробовали Googling сообщение об ошибке? Это, наверное, первое, что вы должны были сделать. Если это не удастся в будущем, задайте вопрос о сообщение об ошибке!


По желанию, примером может быть, если я вход «Hello» в качестве строки secretWord.

Я предполагаю, что secretWord объявлен как char secretWord[] = "Hello"; в вашем примере, и неchar *secretWord = "Hello";. Эти два типа: отличные, и ваша книга должна прояснить это. Если нет, то какую книгу вы читаете? Возможно, вы, возможно, порекомендуете книгу лучше.

Любая попытка изменить строковый литерал (т. Е. char *array = "Hello"; flushArray(array, ...)) является неопределенным поведением, что объясняется ответами this question (среди многих других, я уверен).


Кажется, решение этой проблемы может быть доступно при использовании something like this ...

+0

Приносим извинения за недостаток знаний функции 'memset' и' strncpy', поскольку я учащийся. Я все еще понимаю, как работает этот язык, и я открыт для обучения. Я не понимал, что мой MCVE был не слишком длинным и неполным ... У меня есть весь код для воспроизведения проблемы без инструкций '# include' и трех строк функции main, которые я описал в третьем последний абзац. – Omninano

+0

Да, я делал Google для решений, используя множество разных формулировок, и даже напрямую использовал поиск переполнения стека с несколькими разными формулировками. Ничто из того, что я мог найти, специально не рассматривало проблему, как моя, поэтому почему я в конечном итоге сделал этот пост. Четыре возможных дублированных вопроса, которые вы связывали, не охватывали ту же проблему, что у меня есть, но спасибо за попытку помочь мне найти ресурсы, чтобы помочь мне. В моей программе нет сообщений об ошибках. Он просто продолжает подсвечивать «Никакие символы не разрешены ...» и запрашивает новый ввод снова и снова, независимо от того, какой вклад вы ему даете. – Omninano

1

В ответ на ваш комментарий, вы, вероятно, делает его немного сложнее на себя, чем это должно быть. У вас есть два вопроса (один из которых вы не видите). Вводится первая проверка на вход для подтверждения только a-zA-Z0-9. (ты знаешь что). Во-вторых, вам нужно идентифицировать и удалить trailing'\n', который был прочитан и включен в ваш ввод fgets. (Что один может быть отключение вас)

Вы не показывают, как начальная array заполнена, но, учитывая ваше использование fgets на secretWord[1], я подозреваю, что вы также используете fgets для array. Это именно то, что вы должны использовать. Тем не менее, вы должны удалить '\n', включенный в конце буфера, заполненного fgets, прежде чем позвонить checkforsymbols. В противном случае у вас есть символ 0xa ('\n') в конце, что, конечно же, не a-zA-Z0-9 и приведет к сбою вашего чека.

Чтобы удалить завершающий '\n', все, что вам нужно сделать, это проверить последний символ в вашем буфере. Если это '\n', просто перепишите его нуль-оканчивающимся символом (либо 0, либо эквивалентное представление символа '\0' - ваш выбор). Вам просто нужен length строки (которую вы получаете с strlen от string.h), а затем установите if (string[len - 1] == '\n'). Например:

size_t len = strlen (str);   /* get length of str */ 
    if (str[len - 1] == '\n')   /* check for trailing '\n' */ 
     str[--len] = 0;     /* overwrite with nul-byte */ 

Третья проблема, важно, но не имеет прямое отношение к сравнению, чтобы всегда выбирать type для вашей функции, возвращающей индикацию успеха/неудач по мере необходимости. В вашем случае выбор void не дает вам ничего проверить, чтобы определить, были ли найдены какие-либо символы или нет. Вы можете выбрать любой тип, который вам нравится int, char, char * и т. Д. Все это позволит вернуть значение для оценки успеха или сбоя. Для тестирования строк нормальный выбор - char *, возвращающий действительный указатель на успех или NULL при сбое.

Четвертый вопрос при приеме входного сигнала всегда нужно обрабатывать случай, когда пользователь выбирает для отмены ввода путем создания ручного EOF либо Ctrl + D на Linux или Ctrl + Z на Windoze.Возвращение NULL на fgets дает вам эту способность. Но с ним (и с любой другой функцией ввода) вы должны проверить возврат и использовать возвращаемую информацию, чтобы проверить ввод пользователя. Просто проверьте, возвращает ли fgetsNULL по вашему запросу для ввода, например.

if (!fgets (str, MAXS, stdin)) { /* read/validate input */ 
     fprintf (stderr, "EOF received -> user canceled input.\n"); 
     return 1; /* change as needed */ 
    } 

Для вашего конкретного случая, когда вы хотите только a-zA-Z0-9, все, что вам нужно сделать, это перебирать вниз строку введенного пользователя, проверяя каждый символ, чтобы убедиться, что это a-zA-Z0-9 и вернуть неудачу, если что-нибудь еще встречается. Это делается легко, учитывая, что каждая строка в C равна nul-terminated. Таким образом, вы просто назначаете указатель на начало строки (например, char *p = str;), а затем используете либо цикл , либо while для проверки каждого символа, например.

for (; *p != 0; p++) { do stuff } 

, которые могут быть записаны в сокращенном:

for (; *p; p++) { do stuff } 

или использовать while:

while (*p) { do stuff; p++; } 

Положив все эти куски вместе, вы могли бы написать функцию, чтобы принять строку в качестве только параметр и return NULL, если встречается символ, или верните указатель на исходную строку при успешном выполнении, например

char *checkforsymbols (char *s) 
{ 
    if (!s || !*s) return NULL;  /* validate string and not empty */ 
    char *p = s;     /* pointer to iterate over string */ 

    for (; *p; p++)  /* for each char in s */ 
     if ((*p < 'a' || *p > 'z') && /* char is not a-z */ 
      (*p < 'A' || *p > 'Z') && /* char is not A-Z */ 
      (*p < '0' || *p > '9')) { /* char is not 0-9 */ 
      fprintf (stderr, "error: '%c' not allowed in input.\n", *p); 
      return NULL; /* indicate failure */ 
     } 

    return s; /* indicate success */ 
} 

Короткий полный тест процедура может быть:

#include <stdio.h> 
#include <string.h> 

#define MAXS 256 

char *checkforsymbols (char *s); 

int main (void) { 

    char str[MAXS] = ""; 
    size_t len = 0; 

    for (;;) {        /* loop until str w/o symbols */ 
     printf (" enter string: ");   /* prompt for user input */ 
     if (!fgets (str, MAXS, stdin)) { /* read/validate input */ 
      fprintf (stderr, "EOF received -> user canceled input.\n"); 
      return 1; 
     } 
     len = strlen (str);     /* get length of str */ 
     if (str[len - 1] == '\n')   /* check for trailing '\n' */ 
      str[--len] = 0;     /* overwrite with nul-byte */ 
     if (checkforsymbols (str))   /* check for symbols */ 
      break; 
    } 

    printf (" valid str: '%s'\n", str); 

    return 0; 
} 

char *checkforsymbols (char *s) 
{ 
    if (!s || !*s) return NULL;  /* validate string and not empty */ 
    char *p = s;     /* pointer to iterate over string */ 

    for (; *p; p++)  /* for each char in s */ 
     if ((*p < 'a' || *p > 'z') && /* char is not a-z */ 
      (*p < 'A' || *p > 'Z') && /* char is not A-Z */ 
      (*p < '0' || *p > '9')) { /* char is not 0-9 */ 
      fprintf (stderr, "error: '%c' not allowed in input.\n", *p); 
      return NULL; /* indicate failure */ 
     } 

    return s; /* indicate success */ 
} 

Пример использования/выход

$ ./bin/str_chksym 
enter string: mydoghas$20worthoffleas 
error: '$' not allowed in input. 
enter string: Baddog! 
error: '!' not allowed in input. 
enter string: Okheisagood10yearolddog 
valid str: 'Okheisagood10yearolddog' 

или если пользователь отменяет ввод данных пользователем:

$ ./bin/str_chksym 
enter string: EOF received -> user canceled input. 

сноски 1.

С, как правило предпочитает использовать все нижнего регистра имен переменных, при сохранении всех верхнего регистра для макросов и определяет. Оставьте MixedCase или camelCase имена переменных для C++ и java. Однако, поскольку это вопрос стиля, это полностью зависит от вас.