如何检查索引是否包含符号?

时间:2017-02-13 02:19:34

标签: c arrays

我想检查以确保包含在名为secretWord的数组中的给定字符串中没有符号(例如$%&#)。如果它中有符号,我会让用户重新输入字符串。它利用递归来继续询问,直到它们输入不包含符号的字符串。

接受的唯一符号是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语句?

如果你们中的任何人想知道&#34; flushArray&#34;我使用的方法是,这里是:

    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

在main()方法的第三行调用此函数,紧接在第一行上的print语句后,要求用户输入一个单词,第二行上的fgets()语句获取输入这个checkForSymbols函数用于。

根据要求,一个例子是如果我输入&#34;你好&#34;作为secretWord字符串。然后程序在其上运行函数,if语句由于某种原因被触发,导致它

  1. 将存储在secretWord数组中的所有值替换为ASCII值0.(AKA NULL)
  2. No symbols are allowed in the word. Please try again:打印到控制台。
  3. 等待它将存储在secretWord数组中的新输入。
  4. checkForSymbols()
  5. 中存储的这些新值调用secretWord方法

    无论你输入什么作为新的secretWord,checkForSymbols()方法的if语句都会触发,它会重复步骤1 - 4。

    感谢您在帮助下保持耐心和理解!

3 个答案:

答案 0 :(得分: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 
 }
如果您的数组未以null结尾,则使用

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); 
 }

答案 1 :(得分:1)

  

我接受的唯一符号是NULL符号(ASCII值为零表示的符号)。这是因为我使用NULL符号填充数组中的所有空白区域。

NULL是一个指针;如果您想要字符值0,则应使用0'\0'。我假设您使用memsetstrncpy来确保尾随字节为零?没有......真可惜,你的MCVE可能会短得多(而且完整)。 :(

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

根据C标准的7.4p1部分,......

  

在所有情况下,参数都是一个int,其值应表示为unsigned char或者等于宏EOF的值。如果参数具有任何其他值,则行为未定义。

并非所有char值都可以表示为unsigned char或等于EOF,因此它可能(并且极有可能给出这个问题的本质)上面的代码调用了未定义的行为。

由于您尚未完成问题(通过提供MCVE,并描述正在发生的错误),我假设您提出的问题尝试提问可能会与this questionthis questionthis questionthis question以及可能还有很多其他人重复...如果是这样,那么你呢?尝试 Google搜索错误消息?这可能是你应该做的第一件事。如果将来失败,请提出问题关于错误消息!

  

根据要求,一个例子是如果我输入&#34;你好&#34;作为secretWord字符串。

我认为您的示例中secretWord被声明为char secretWord[] = "Hello";,而不是 char *secretWord = "Hello";。这两种类型是 distinct ,您的书应该澄清这一点。如果没有,你正在读哪本书?如果您愿意,我可以推荐一本更好的书。

任何修改字符串文字(即char *array = "Hello"; flushArray(array, ...))的尝试都是未定义的行为,正如this question的答案所解释的那样(我确定其中很多)。

似乎可以使用something like this ...

来解决此问题

答案 2 :(得分:1)

在回应你的评论时,你可能会让自己比你需要的更加强硬。你有两个问题要处理(一个你没有看到)。输入第一个检查输入以仅验证a-zA-Z0-9的输入。 (你知道的)。第二个是您需要识别并删除尾随 '\n'读取,并通过fgets包含在您的输入中。 (那个人可能会绊倒你)

您不会显示最初的array是如何填写的,但考虑到您在fgets [1] 上使用secretWord,我怀疑您还在fgets使用array。这正是你应该使用的。但是,在致电'\n'之前,您需要删除fgets填充缓冲区末尾的checkforsymbols。否则,您最后会遇到0xa'\n')字符,当然,这不是a-zA-Z0-9,会导致您的支票失败。

要删除尾随'\n',您需要做的就是检查缓冲区中的最后一个字符。如果是'\n',则只需使用 nul-terminatedating 字符(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的选择使您无需检查以确定是否找到任何符号。您可以选择您喜欢的任何类型intcharchar *等。所有类型都允许返回值来衡量成功或失败。对于测试字符串,正常选择为char *,在成功时返回有效指针,或在失败时返回NULL

获取输入时的第四个问题是,您始终需要通过在Linux或 ctrl + d 的手动EOF来处理用户选择取消输入的情况在windoze上> ctrl + z 。 NULL fgets的返回为您提供了这种能力。但是使用它(以及其他所有输入函数),您必须检查返回并使用返回信息以验证用户输入。只需检查fgets是否在您的输入请求中返回NULL,例如

    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;),然后使用forwhile循环来检查每个字符,例如

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

可以用速记写的:

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

或使用while

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

将所有这些部分组合在一起,您可以编写函数以将字符串作为唯一参数,如果遇到符号则返回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。

C通常更喜欢使用所有小写变量名,同时为宏保留所有大写并定义。保留C ++和java的 MixedCase camelCase 变量名。但是,由于这是一个风格问题,这完全取决于你。