C: validating input array elements - c

The code prompts user to enter a string with mixed types of values (the string could contain single-digit integers, special characters like '-' or single characters) and input is stored letter-by-letter into a character array char array[10].
Then I wrote a for loop to loop through each element to check if there is any invalid characters (i.e. not a single-digit integer, special characters that is not '-', or single characters that is not my choice).
However, no matter what the input is (even the input only contains wanted characters), error message for invalid characters always shows up. I checked what is stored in the array by printing each element one by one and they seemed fine. How should I fix my code for the purpose?
int main(void){
char in[10];
printf("Enter only 0-9 or '-' or 'w':");
scanf("%s", in);
getchar();
int i;
for(i = 0; i < 11; i++){
while(in[i] != '0' || in[i] != '1' || in[i] != '2' || in[i] != '3' ||
in[i] != '4' || in[i] != '5' || in[i] != '6' || in[i] != '7' ||
in[i] != '8' || in[i] != '9' || in[i] != '-' || in[i] != 'x')
{
printf("Error: Invalid input\n");
printf("Enter another one:");
scanf("%s", in);
getchar();
i = 0;
}
}
}

Condition in[i] != '0' || in[i] != '1' ... will always be true, since a single character is always either !='0' or !='1'. You probably meant in[i] != '0' && in[i] != '1'.
And it should be for(i = 0; i < 10; i++), not 11, since this would exceed array bounds.

The error is because your iteration condition should be i < 10 (otherwise you are accessing the position 10, which is out of the array limits).
You should also check for the character \0, which indicates the end of a string, and stop checking the password.
You should also be checking your conditions with &&, as Stephen pointed out.
You should use an if instead of a while, otherwise you'd enter an infinite loop.
As other users pointed out, the getchar() is not necessary.
Finally, you can do your checks in a nicer way like this:
if ((in[i] < '0' || in[i] > '9') && in[i] != '-' && in[i] != 'x') {
// bad character found
}
You should also wrap all this into a while(badInput == true), instead of calling scanf inside your checking.
I'd implement everything this way:
char in[10];
bool badInput = true;
while (badInput) {
printf("Enter only 0-9 or '-' or 'w':");
scanf("%s", in);
badInput = false;
if (in[0] == '\0') {
// no input, whoops
badInput = true;
}
for (int i = 0; i < 10 && !badInput && in[i] != '\0'; i++) {
if ((in[i] < '0' || in[i] > '9') && in[i] != '-' && in[i] != 'x') {
badInput = true;
printf("Error: Invalid input\n");
}
}
}

Related

Can someone explain me why I am not able to check special characters in my string using ASCII values?

So, my code actually works perfectly when I use function that checks for special characters in string by explicitly giving symbols:
int isSpecialCharacter(char str[], int n)
{
for(int i=0; i<n;i++)
{
if (str[i] == '!' || str[i] == '#' || str[i] == '#' || str[i] == '$' || str[i] == '%' || str[i] == '^' || str[i] == '(' || str[i] == ')')
{
return 1;
}
return 0;
}
}
However, in the below code I am not able to get my code to find special characters in string using ASCII values. I want to understand what am I doing wrong. In the below code, I have my main() also included that prompts the user to input string.
#include <stdio.h>
#include <string.h>
char str[30][30];
char test[100];
int myindex = 0;
int isSpecialCharacter(char str[], int n)
{
for(int i=0; i<n;i++)
{
if (str[i] == 33 || str[i] == 35 || str[i] == 36 || str[i] == 37 || str[i] == 40 || str[i] == 41 || str[i] == 64)
{
return 1;
}
return 0;
}
}
int main()
{
printf("Please enter 10 strings below: \n");
while(myindex < 10)
{
printf("Enter string %d: ", myindex+1);
fgets(str[myindex], 500, stdin);
strcpy(test, str[myindex]);
int t_size = strlen(test);
if (strlen(str[myindex])<2||strlen(str[myindex])>26)
{
printf("Enter string that is between 2 and 25");
continue;
}
else if(isSpecialCharacter(test, t_size) == 1)
{
printf("Your string has some special characters. \n");
continue;
}
else
{
myindex++;
}
}
return 0;
}
EDIT:
I have included the variable declarations and replaced the code where I use symbols to check for special characters. Thank you.
EDIT2:
These are the characters that I want to look for: : ’!’, ’#’, ’#’, ’$’, ‘%’, ‘^’, ’(’, or ’)’. Not spaces.
Both your functions won't work as you've written them.
The main problem is that the for loop returns after each loop cycle, so you never check beyond the first cycle.
You should move the return 0 statement to the end of the function, then it will work as expected.
int isSpecialCharacter(char str[], int n)
{
for (int i = 0; i < n; i++)
{
if (str[i] == 33 || str[i] == 35 || str[i] == 36 || str[i] == 37 || str[i] == 40 || str[i] == 41 || str[i] == 64)
{
return 1;
}
}
return 0;
}
Test
I've tested the solution with the following input:
test1
test2
test)
test(
test3
test4
test5
test#
test6
test7
test!
test8
test9
test10
And it works. You can see the result there: https://godbolt.org/z/67Px14z75
As suggested from other users in the comment section, using decimal values to refer to characters is a bad practice™ and you should stick with the '#' notation.
Your return 0; is incorrect:
int isSpecialCharacter(char str[], int n) {
for(int i=0; i<n;i++)
{
if (str[i] == '!' || str[i] == '#' || str[i] == '#' || str[i] == '$' || str[i] == '%' || str[i] == '^' || str[i] == '(' || str[i] == ')')
{
return 1;
}
return 0;
}
}
On the very first loop, your function returns either 1 or 0. You only want to return 0 (false) if the loop completes without finding the character you're looking for.
int isSpecialCharacter(char str[], int n)
{
for(int i=0; i<n;i++)
{
if (str[i] == '!' || str[i] == '#' || str[i] == '#' || str[i] == '$' || str[i] == '%' || str[i] == '^' || str[i] == '(' || str[i] == ')')
{
return 1;
}
}
return 0;
}
I'm not going to try to write your code...
if( isSpecialCharacter()
is equivalent to:
if( strpbrk( test, "abqmz" ) != NULL )
(except that the latter has been proven to work...)
If a, b, q, m, z appear in the string, then the if condition is true...
Learn the standard library instead of spending time badly reinventing it...
EDIT:
Here is how an experienced programmer might write that functionality now that you've decoded the decimal ASCII values. (Don't expect the next programmer who reads your code to reach for their ASCII table...)
char spcl[] = "!##$%^()";
if( strpbrk( test, spcl ) != NULL ) {
// Do something because condition is true
NB: if you need to make either \ or " special inside a string, you must 'escape' either of those characters with an 'extra' backslash. Eg:
char spcl[] = "\\!##$%^(\")"; // notice '\\' and '\""
If that looks too much like "bad language", you can construct your own string (ENSURING(!) that it is null terminated.)
char spcl[] = { '\\', '!', '#', '#', '$', '%', '^', '(', '\"', ')' '\0' };
And...
char str[30][30];
/* Skipping ahead */
printf("Enter string %d: ", myindex+1);
fgets(str[myindex], 500, stdin); // 500!!! ????
is simply looking for trouble...
The position of "return 0" is not correct.
It should come after the end of "for loop"

What is causing the new line character to not work in my program?

I am not sure why my new line is not working for printf(operand1, "%s\n"); I print test afterwards and its not on a new line.
#include <stdio.h>
int main(){
printf("Enter elementary operation:"); //Output to console for user to see
char input[32]; //Create a char array of size 32 characters (32 bytes or 256 bits), can only store 255 due to needing the end string character which is '\0'
fgets(input, sizeof(input), stdin); //get line that user inputs
printf(input,"%s\n"); //print the string the user input
char operand1[32];
int i = 0;
while(input[i] == '0' || input[i] == '.' || input[i] == '1' || input[i] == '2' || input[i] == '3' || input[i] == '4'
|| input[i] == '5' || input[i] == '6' || input[i] == '7' || input[i] == '8' || input[i] == '9' || (i == 0 && input[i] == '-')){
operand1[i] = input[i];
i++;
}
printf(operand1, "%s\n");
printf("test");
return 0;
}
Output is:
Enter elementary operation:99+0
99+0
99test%
First, it should be printf("%s\n",operand1). What happens in your code is that operand1 is treated as format string and since it doesn't have % in it, it is printed as is.
Second, your operand1 doesn't have zero byte after the copied chars, so it's not really a string from C's point of view and when you pass it to printf with %s format option printf will print your memory content until it accidentally hits a 0. Although, perhaps this behavior won't happen, because when you allocate an array it might be pre-initialized with zeros - depends on lots of things. It is more correct and safe to add operand1[i] = '\0' after the loop
Third, there is isdigit function (defined in <ctype.h>), that you can use i/o testing manually for all the digits. Or you can use comparison (input[i] >= '0' && input[i] <= '9')

Find spaces and alphanumeric characters in a string C Language

Hi i'm trying to build a function in C language that checks if the string contains numbers , upper cases and lower cases and space, if the string contains any other character then those the function return -1.
float avg_word_len(char* str)
{
float check;
for (int i = 0; i < strlen(str); i++)
{
if (((str[i] >= '0') && (str[i] <= '9')&&(str[i] >= 'a') && (str[i] <= 'z') && (str[i] == ' ')&& (str[i] >= 'A') && (str[i] <= 'Z')))
check = 1;
else
check = -1;
}
str = '\0';
return check;
that's my code ,but the function keep return -1 please help
Some of your && must replaced by || because one character is a number OR a lower case OR a space OR an upper case, but it cannot be all these things at a time :
check = 1;
for (int i = 0; i < strlen(str); i++)
{
if (! (((str[i] >= '0') && (str[i] <= '9')) ||
((str[i] >= 'a') && (str[i] <= 'z')) ||
(str[i] == ' ') ||
((str[i] >= 'A') && (str[i] <= 'Z')))) {
check = -1;
break;
}
}
You can use these three function which are countain in the hreader #include <ctype.h>
isalpha : Checks if a character is alphabetic (upper or lower case).
isdigit : Checks if a character is a number.
isblank : Checks whether a character is blank or not.
#include <ctype.h>
#include <stdio.h>
float avg_word_len(char* string)
{int check=-1;
for(int i=0;string[i]!='\0';i++)
{
if(isalpha(string[i])||isdigit(string[i])||isblank(string[i]))
{
check=1;
}
}
return check;
}
int main()
{
char string[150];
printf("Give me a text :");
scanf("%s[^\n]",string);
printf("\n%.f\n",avg_word_len(string));
}
As Weather Vane commented, a lot of those &&s should be ||s - additionally, parentheses should surround each range (e.g. ('0' <= str[i] && str[i] <= '9'))).
To check whether the character is in a range, we use AND (i.e. the character is above the lower bound AND below the upper bound). To check whether the character is in one of multiple ranges, we use OR (i.e. the character is in range 1 OR it is in range 2 OR...).
If we were to only fix that, here's how the if condition would look:
(str[i] >= '0' && str[i] <= '9') || (str[i] >= 'a' && str[i] <= 'z') || (str[i] == ' ') || (str[i] >= 'A' && str[i] <= 'Z')
Having said that, I would suggest using the function isalnum from ctype.h in the standard library, which checks if a character is alphanumeric. It makes the code much simpler and avoids the assumption that characters are ordered in such a way that all lowercase letters lie between 'a' and 'z' (which is true in ASCII - which is what is used in practice - but is not standard).
In addition, I would suggest initializing check to -1 and breaking early from the loop once you find a non-alphanumeric, non-space character so that a -1 is not later overwritten by a 1 (as would happen in the current version of your code).
This is what it would look like:
float check = -1;
for (int i = 0; i < strlen(str); i++)
{
if (!isalnum(str[i]) && str[i] != ' ') {
check = 1;
break;
}
}

reading space character into string with size determined by str_size

I'm trying to make this program such that the user could type any given string of characters, and the program would separate alphanumerical characters from the rest, print them into a second string, and finally print the final result into the screen.
I've already tried using scanf ("%[^\n]%*c", string);, but it doesn't seem to work since the size of the string is not specified beforehand, and is rather defined by STR_SIZE.
char string[STR_SIZE];
printf("please type in a string \n");
scanf("%s", string);
printf("string: \n %s \n", string);
int size = (strlen(string));
char alfanumerico[STR_SIZE];
int count = 0;
int count2 = 0;
while(count <= size)
{
if(string[count] >= '0' && string[count] <= '9')
{
alfanumerico[count2] = string[count];
count2++;
}
if(string[count] >= 'a' && string[count] <= 'z')
{
alfanumerico[count2] = string[count];
count2++;
}
if(string[count] >= 'A' && string[count] <= 'Z')
{
alfanumerico[count2] = string[count];
count2++;
}
if(string[count] ==' ')
{
alfanumerico[count2] = string[count];
count2++;
}
count++;
}
printf("alphanumerical characters typed: \n %s \n", alfanumerico);
Given the user typed a string such as: -=-=[[][][]}}Hello 123 ```//././.
I expect the output to be: Hello 123
scanf is not the way to go, especially if your input might contain white-spaces on which scanf would stop reading more inputs and wouldn't store spaces for instance.
You should use fgets which lets you limit the input data according to the buffer this data is stored in. So something like:
fgets(string, STR_SIZE, stdin)
should work.
About the size - you should have some limitation about the maximum size of the string and then STR_SIZE should be set to this number. It should be part of your program requirements or just a size that makes sense if you're making the requirements. It must be defined before you're reading input from the user because the buffer memory is allocated before reading to it.
A comment about style, unrelated to your question - always try to decrease code duplication to 0. The line alfanumerico[count2] = string[count]; count2++; appears 4 times in your code. A more elegant minimal if statement with exactly the same functionality would be:
if ((string[count] >= '0' && string[count] <= '9') ||
(string[count] >= 'a' && string[count] <= 'z') ||
(string[count] >= 'A' && string[count] <= 'Z') ||
(string[count] == ' '))
{
alfanumerico[count2] = string[count];
count2++;
}
and to be even more minimal:
char c = string[count];
if ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == ' '))
{
alfanumerico[count2] = c;
count2++;
}
It's also more readable and more maintainable - if you want to change the variable count to i you do it in one place instead of 8.
Also, always close a scope in a new line.

How to count vowels, consonants, digits in a txt file using redirection in C

Brand new C coder here. In my first C course in school. I have experience in java but this course is all in C. I have homework to create a program that reads the contents of a file and counts the number of upper and lower case letters, vowels, consonants and digits. The program is not supposed to have any arguments, but will take a .txt file from the command line via redirection. My question is, how do I correct my current code to read from stdin each character of the file, whether it be a letter or a number? I'm really struggling with how read the contents of the file from stdin, read each character and then decide which category it belongs in. Any help would be appreciated. Thanks.
I'll be running the program like this...
$ program < testFile.txt
Where testFile.txt will contain the following text:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
int upper = 0; // Number of upper case letters
int lower = 0; // Number of lower case letters
int vowel = 0; // Number of vowels
int consonant = 0; // Number of constants
int digits = 0; // Number of digits
int total = 0; // Total number of characters in file
int i =0;
char value[100];
fgets(value, 100, stdin);
while(value[i] != '\0');
{
if (value[i] >= 'A' && value[i] <= 'Z')
{
upper++;
if (value[i] == 'A' || value[i] == 'E' || value[i] == 'I' || value[i] == 'O' || value[i] == 'U' || value[i] == 'Y')
{
vowel++;
}
else {
consonant++;
}
}
else if (value[i] >= 'a' && value[i] <= 'z')
{
lower++;
if (value[i] == 'a' || value[i] == 'e' || value[i] == 'i' || value[i] == 'o' || value[i] == 'u' || value[i] == 'y')
{
vowel++;
}
else {
consonant++;
}
}
else if (value[i] >= '0' && value[i] <= '9')
{
digits++;
}
total++;
i++;
}
printf("upper-case: %d", upper);
printf("\nlower-case: %d", lower);
printf("\nvowels: %d", vowel);
printf("\nconsonants: %d", consonant);
printf("\ndigits: %d", digits);
printf("\ntotal: %d", total);
printf("\n");
return 0;
I expect output to show how many upper case letters, lower case letters etc.
But once I run $ program < testFile.txt, it just sits there, no output to command line or anything.
Remove the semicolon after the while statement. :-)
while(value[i] != '\0');
This is your most obvious problem, it basically means:
while value[i] != '\0':
do nothing
end while
In other words, if it enters the loop, it will never exit it, because nothing changes that would affect the condition under which the loop continues.
There are other problems as well such as the fact that you will only process the first line rather than the whole file. The whole idea of using fgets and processing a line is unnecessary when you can just start with the following filter skeleton:
int ch;
while ((ch = getchar()) != EOF) {
/* process ch */
}
This will process an entire file character by character until all characters are done (or until an error occurs) so you can just tailor the body loop to do what you need - you've basically done that bit in your code with the loop over the line characters.
I would suggest not using the following code (since this is classwork) but you can also make better use of flow control constructs and library functions (from ctype.h and string.h), something like:
while ((ch = getchar()) != EOF) {
// Lib functions to detect upper/lower-case letters.
if (isupper(ch)) {
++upper;
} else if (islower(ch))
++lower;
}
// And to detect letter/digit type.
if (strchr("aeiouAEIOU", ch) != NULL) {
++vowel;
} else if (isalpha(ch)) {
++consonant;
} else if (isdigit(ch)) {
++digits;
}
++total;
}
This is particularly important since there's no actual guarantee that non-digit characters will be consecutive.

Resources