我想检查以确保包含在名为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
语句由于某种原因被触发,导致它
secretWord
数组中的所有值替换为ASCII值0.(AKA NULL)No symbols are allowed in the word. Please try again:
打印到控制台。secretWord
数组中的新输入。checkForSymbols()
。secretWord
方法
醇>
无论你输入什么作为新的secretWord,checkForSymbols()
方法的if
语句都会触发,它会重复步骤1 - 4。
感谢您在帮助下保持耐心和理解!
答案 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'
。我假设您使用memset
或strncpy
来确保尾随字节为零?没有......真可惜,你的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 question,this question,this question,this 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
的选择使您无需检查以确定是否找到任何符号。您可以选择您喜欢的任何类型int
,char
,char *
等。所有类型都允许返回值来衡量成功或失败。对于测试字符串,正常选择为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;
),然后使用for
或while
循环来检查每个字符,例如
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 变量名。但是,由于这是一个风格问题,这完全取决于你。