Segmentation Fault When Parsing Char Arrays - c

I am working on a function that takes a string parameter (actually sending a char array from the main function, but don't think that makes a difference) in C, and parses the string to be stored in a linked list (it is an assignment for school) and am receiving a segmentation fault. I have added strings to be printed throughout the program in order to debug the program, because it relies on an input file, and I do not know how to start gdb with an input option.
This is what my function looks like:
Token * list_head = NULL;
Token * current = NULL;
char line_segment[MAX_PRINT_LINE_LENGTH + 1];
int i, pos = 0; //In the for loop, we do not not to lose the pos in the array
puts("in token.c, beginning segmentation");
/***************************************************************************
* Loop through the possibilites of the first character starting at the
* position located at the pointer (pretty sure this is still easier on the
* memory and logically then enumerating all of the different symbols and
* types of chars that you will see.
**************************************************************************/
for(i=0; line_copy[pos] != '\0';){
if(line_copy[pos] == 'a' || 'b' || 'c' || 'd' || 'e' || 'f' || 'g' ||
'h' || 'i' || 'j' || 'k' || 'l' || 'm' || 'n' ||
'o' || 'p' || 'q' || 'r' || 's' || 't' || 'u' ||
'v' || 'w' || 'x' || 'y' || 'z' || 'A' || 'B' ||
'C' || 'D' || 'E' || 'F' || 'G' || 'H' || 'I' ||
'J' || 'K' || 'L' || 'M' || 'N' || 'O' || 'P' ||
'Q' || 'R' || 'S' || 'T' || 'U' || 'V' || 'W' ||
'X' || 'Y' || 'Z') //Identifier or Rw
do{
line_segment[i] = line_copy[pos];
pos++; i++;
} while(line_copy[pos] == //All letters of alphabet);
else if(line_copy[pos] == '0' || '1' || '2' || '3' || '4' || '5' ||
'6' || '7' || '8' || '9'){ //Number
do{
line_segment[i] = line_copy[pos];
pos++; i++;
} while(line_copy[pos] == '0' || '1' || '2' || '3' || '4' || '5' ||
'6' || '7' || '8' || '9' || 'e');
}
else if(line_copy[pos] == " "){ //No token
line_segment[i] = '\0';
pos++;
}
else if(line_copy[pos] == "'"){ //String
do{ //We want to keep the first apostrophe for make_node
line_segment[i] = line_copy[pos];
pos++; i++;
} while(line_copy[pos] != "'");
pos++; //Don't want to start on the ending ' symbol.
}
else{ //Symbol
line_segment[i] = line_copy[pos];
pos++;
}
puts("line segmented, attempting node");
printf("line segment: %s\n", line_segment);
current = make_node(line_segment);
memset(line_segment, '\0', MAX_PRINT_LINE_LENGTH);
puts("attempting to add node to list");
list_head = add_to_list(list_head, current);
free(current);
puts("node freed");
}
return list_head;
}

if(line_copy[pos] == 'a' || 'b' || 'c' || 'd' || 'e' || 'f' || 'g' ||
'h' || 'i' || 'j' || 'k' || 'l' || 'm' || 'n' ||
'o' || 'p' || 'q' || 'r' || 's' || 't' || 'u' ||
'v' || 'w' || 'x' || 'y' || 'z' || 'A' || 'B' ||
'C' || 'D' || 'E' || 'F' || 'G' || 'H' || 'I' ||
'J' || 'K' || 'L' || 'M' || 'N' || 'O' || 'P' ||
'Q' || 'R' || 'S' || 'T' || 'U' || 'V' || 'W' ||
'X' || 'Y' || 'Z')
You have to follow the actual C syntax. You can't make things up and expect them to work. You are ORing a bunch of letters, which doesn't make any sense.

Try using isalpha() and isdigit()functions from ctype.h.

Related

Keep getting warning "Suggest parentheses around '&&' within '||' for C program [duplicate]

This question already has answers here:
Why does Clang warn: `'&&' within '||'`?
(2 answers)
Closed 12 months ago.
printf(" 1| %d | %d | %d | %d | %d\n",
((coffee_strength == 'm' || coffee_strength == 'M') &&
(coffee1_type == 'l' || coffee1_type == 'L') ||
(coffee_strength == 'r' || coffee_strength == 'R') &&
(coffee1_type == 'b' || coffee1_type == 'B')),
((coffee_maker == 'r' || coffee_maker == 'R') &&
(coffee1_grindSize == 'c' || coffee1_grindSize == 'C') ||
(coffee_maker == 'C' || coffee_maker == 'c') &&
(coffee1_grindSize == 'f' || coffee1_grindSize == 'F')),
((coffee_servings >= 1) && (coffee_servings <= 4) &&
(coffee1_weight >= 0) && (coffee1_weight <= 250) ||
((coffee_servings >= 1) && (coffee_servings <= 9) &&
(coffee1_weight == 500)) ||
((coffee_servings >= 10) && (coffee1_weight == 1000))),
(((coffee_cream == 'y' || coffee_cream == 'Y') &&
(coffee1_cream == 'y' || coffee1_cream == 'Y') ||
(coffee_cream == 'n' || coffee_cream == 'N') &&
(coffee1_cream == 'n' || coffee1_cream == 'N'))),
((coffee1_temp >= 60.0) && (coffee1_temp <= 69.9) &&
(coffee_maker == 'r' || coffee_maker == 'R') ||
((coffee1_temp >= 70.0) && (coffee_maker == 'c' || coffee_maker == 'C'))));
This is my code that I am trying to compile. Everytime I run it I still get the issue related to bracket placement. I have edited my code many times to try and solve this but the issue still persists. Does anyone have any suggestions as to what I should do?
Operator && has higher precedence than operator ||. Therefore, though legal, the compiler is telling you code that does this:
a && b || c && d
May not be doing what you intended. The compiler will treat that as
(a && b) || (c && d)
but for all it knows, you intended any one of a number of other things.
Perhaps this:
a && (b || (c && d))
or... this:
((a && b) || c) && d
Or maybe... this:
a && (b || c) && d
etc.
It makes a difference, and mistakes like this are common, so although your code will compile, it will do so with warnings when appropriately asked to do so (and it's always appropriate to ask). Not because it is wrong, but rather because you didn't make intent clear enough that the warning monkeys were subdued (which in this case, and most cases, is a good thing) To ensure you get what you expected, the compiler is asking you to clarify your expression via parenthesis. The -Wlogical-op-parentheses, included with -Wall, is the likely candidate telling you this if you're using gcc or clang.
By the looks of it, you've taken up the mantle of trying to address this, but you missed several instances. For example:
((coffee_servings >= 1) && (coffee_servings <= 4) &&
(coffee1_weight >= 0) && (coffee1_weight <= 250) || // <== here
((coffee_servings >= 1) && (coffee_servings <= 9) &&
(coffee1_weight == 500)) ||
((coffee_servings >= 10) && (coffee1_weight == 1000)))
There are others below, which I leave for you to find (they're pretty obvious once you start nesting your parens and realize just how many places a && b || c pops up).
(((coffee_cream == 'y' || coffee_cream == 'Y') &&
(coffee1_cream == 'y' || coffee1_cream == 'Y') ||
(coffee_cream == 'n' || coffee_cream == 'N') &&
(coffee1_cream == 'n' || coffee1_cream == 'N'))),
and here:
((coffee1_temp >= 60.0) && (coffee1_temp <= 69.9) &&
(coffee_maker == 'r' || coffee_maker == 'R') || // <== here
((coffee1_temp >= 70.0) && (coffee_maker == 'c' || coffee_maker == 'C')))
Sorry to say, but that seems like making out everything by looking at space. There are millions of stars, planets, asteroids, comets, meteors.
But I extremely appreciate your effort on formatting. Not a joke.
The problem seems to be here:
&& (coffee1_temp <= 69.9) &&
(coffee_maker == 'r' || coffee_maker == 'R') ||
((coffee1_temp >= 70.0) && (coffee_maker == 'c' || coffee_maker == 'C'))));
Let's expand it:
&& (coffee1_temp <= 69.9) && (coffee_maker == 'r' || coffee_maker == 'R') || ((coffee1_temp >= 70.0) && (coffee_maker == 'c' || coffee_maker == 'C'))));
I am not sure what you want to acheive in that line, but here is a example that might fix the error in that line:
&& (coffee1_temp <= 69.9) && ( (coffee_maker == 'r' || coffee_maker == 'R') || ((coffee1_temp >= 70.0) && (coffee_maker == 'c' || coffee_maker == 'C')) ) ));
Why does the error happen?
You have a a || c && d/a && b || c && d. The compiler warns you since you did not tell it what to do in that situation.
Example:
a && c || c && d,
What should happen first? c || c or a && c or c || c && d, etc... Extremely confusing...
Edit:
It also seems like you have this on many other places too.
You could just use separate if statements to make this clearer...after all it seems like it takes more time to read this than to write a new set of if statements.
Hopefully more readable:
(
(coffee_strength == 'm' || coffee_strength == 'M')
&& (coffee1_type == 'l' || coffee1_type == 'L')
|| (coffee_strength == 'r' || coffee_strength == 'R')
&& (coffee1_type == 'b' || coffee1_type == 'B')
),
(
(coffee_maker == 'r' || coffee_maker == 'R')
&& (coffee1_grindSize == 'c' || coffee1_grindSize == 'C')
|| (coffee_maker == 'C' || coffee_maker == 'c')
&& (coffee1_grindSize == 'f' || coffee1_grindSize == 'F')
),
(
(coffee_servings >= 1)
&& (coffee_servings <= 4)
&& (coffee1_weight >= 0)
&& (coffee1_weight <= 250)
|| (
(coffee_servings >= 1)
&& (coffee_servings <= 9)
&& (coffee1_weight == 500)
)
|| (
(coffee_servings >= 10)
&& (coffee1_weight == 1000)
)
),
(
(
(coffee_cream == 'y' || coffee_cream == 'Y')
&& (coffee1_cream == 'y' || coffee1_cream == 'Y')
|| (coffee_cream == 'n' || coffee_cream == 'N')
&& (coffee1_cream == 'n' || coffee1_cream == 'N')
)
),
(
(coffee1_temp >= 60.0)
&& (coffee1_temp <= 69.9)
&& (coffee_maker == 'r' || coffee_maker == 'R')
|| (
(coffee1_temp >= 70.0)
&& (coffee_maker == 'c' || coffee_maker == 'C')
)
)
Now, is it really hard to make out what the issues are?
Fix, THAT MIGHT NOT BEHAVE AS YOU INTENDED:
(
(
(coffee_strength == 'm' || coffee_strength == 'M')
&& (coffee1_type == 'l' || coffee1_type == 'L')
)
|| (
(coffee_strength == 'r' || coffee_strength == 'R')
&& (coffee1_type == 'b' || coffee1_type == 'B')
)
)
(
(
(coffee_maker == 'r' || coffee_maker == 'R')
&& (coffee1_grindSize == 'c' || coffee1_grindSize == 'C')
)
|| (
(coffee_maker == 'C' || coffee_maker == 'c')
&& (coffee1_grindSize == 'f' || coffee1_grindSize == 'F')
)
)
(
(
(coffee_servings >= 1)
&& (coffee_servings <= 4)
&& (coffee1_weight >= 0)
&& (coffee1_weight <= 250)
)
|| (
(coffee_servings >= 1)
&& (coffee_servings <= 9)
&& (coffee1_weight == 500)
)
|| (
(coffee_servings >= 10)
&& (coffee1_weight == 1000)
)
)
(
(
(
(coffee_cream == 'y' || coffee_cream == 'Y')
&& (coffee1_cream == 'y' || coffee1_cream == 'Y')
)
|| (
(coffee_cream == 'n' || coffee_cream == 'N')
&& (coffee1_cream == 'n' || coffee1_cream == 'N')
)
)
)
(
(
(coffee1_temp >= 60.0)
&& (coffee1_temp <= 69.9)
&& (coffee_maker == 'r' || coffee_maker == 'R')
)
|| (
(coffee1_temp >= 70.0)
&& (coffee_maker == 'c' || coffee_maker == 'C')
)
)
And as #user3386109 said, you can simplify statements checking for uppercase and lowercase like a == 'A' || a == 'a' to toupper(a) == 'A' using toupper(int c) and tolower(int c) from <ctype.h>

Last character of numeric string being removed, how to fix this problem in C?

I'm trying to solve a problem with replacing letters with numbers. The user will enter a string, in case there are letters, I must substitute the corresponding number, and in case there are * # - symbols, I must simply remove them.
However, I am facing an issue. When the user types only a numeric string, the last character of this string is being removed, which cannot happen. This can only happen if there are letters or symbols in the string.
Source
#include <stdio.h>
#include <string.h>
void alterChars(char phrase[])
{
int i, dashes = 0;
for (i = 0; phrase[i] != '\0'; i++)
{
if (phrase[i] == 'A' || phrase[i] == 'B' || phrase[i] == 'C')
{
phrase[i] = '2';
}
if (phrase[i] == 'D' || phrase[i] == 'E' || phrase[i] == 'F')
{
phrase[i] = '3';
}
if (phrase[i] == 'G' || phrase[i] == 'H' || phrase[i] == 'I')
{
phrase[i] = '4';
}
if (phrase[i] == 'J' || phrase[i] == 'K' || phrase[i] == 'L')
{
phrase[i] = '5';
}
if (phrase[i] == 'M' || phrase[i] == 'N' || phrase[i] == 'O')
{
phrase[i] = '6';
}
if (phrase[i] == 'P' || phrase[i] == 'Q' || phrase[i] == 'R' || phrase[i] == 'S')
{
phrase[i] = '7';
}
if (phrase[i] == 'T' || phrase[i] == 'U' || phrase[i] == 'V')
{
phrase[i] = '8';
}
if (phrase[i] == 'W' || phrase[i] == 'X' || phrase[i] == 'Y' || phrase[i] == 'Z')
{
phrase[i] = '9';
}
if (phrase[i] == '*' || phrase[i] == '#' || phrase[i] == '-')
{
dashes++;
}
else if (dashes > 0)
{
phrase[i - dashes] = phrase[i];
}
}
phrase[strlen(phrase)-1] = '\0';
printf("%s\n", phrase);
}
int main()
{
char phrase[300];
while (!feof(stdin))
{
scanf(" %[^\n]s", phrase);
alterChars(phrase);
}
return 0;
}
Any tips will be valuable. You can access the problem to see where the error is occurring. Anyway, it's on the last entry, at number 190. It is being printed 19, but in fact it should be printed 190, because the removal of characters should only occur when there are letters, or symbols.
Examples
Input: 333-PORTO
Output: 33376786
The problem:
Input: 190
Output: 19
With your "generous" scanning, i.e. practically no expected syntax, you can simply loop while scanning is successful.
while (1==scanf(" %299[^\n]", phrase)) alterChars(phrase);
That fixes the problem with your while condition ( see Why is “while ( !feof (file) )” always wrong? ).
Then you want to read each line until either newline or terminator:
for (i = 0; phrase[i] != '\0' && phrase[i] != '\n'; i++)
And you want to force-terminate with respect to the dashes.
phrase[strlen(phrase)-dashes] = '\0';
and you get the desired output - and in only one line.... ;-)
The explanation is, if you always terminate as with 1 dash, then it works for 1 dash, fails by cutting too much for zero dashes and does other unwanted stuff for more than one dash, i.e. repeat the last few characters.
It is after all unrelated to "numeric only".
I have incorporated this good input by chux:
scanf(" %[^\n]s" is bad as it has not width limit and 2) the s is pointless.

CS50 Pset6 error 405 keeps on printing server.c

So my code, no matter what, returns error 405 (once the test that only two spaces are in the request-line is passed). Which makes me believe I have made an error in creating a code to determine that "GET" is in fact the first word. This is all my code leading up to the "check" that the method type is "GET" or any capitalization thereof.
int s;
s=0;
int i=0;
for(int q=0; q<strlen(line); q++)
{
if(line[q] == ' ')
s++;
}
if(s!=2)
{
error(400);
return false;
}
if((line[i] != 'g' || line[i] != 'G') || (line[i+1] != 'e' || line[i+1] != 'E') || (line[i+2] != 't' || line[i+2] != 'T')||
(line[i+3] != ' ' ))
{
error(405);
return false;
}
Any reason this would always return false? I have int i initialized to 0.
Any reason this would always return false?
Reason :
consider the if statement as :
if(expression_1 || expression_2 || expression_3 || expression_4)
//where
//expression_1 is (line[i] != 'g' || line[i] != 'G')
//expression_2 is (line[i] != 'e' || line[i] != 'E')
//expression_3 is (line[i] != 't' || line[i] != 'T')
//expression_4 is (line[i] != ' ')
let's consider line as GET
Now, expression_1 is always evaluated to be true even though line[i] == G because line[i] != 'g' is true. Therefore, (line[i] != 'g' || line[i] != 'G') is true as true || false == true
Now further expressions are not evaluated as || is a lazy operator and it stops evaluation on first true occurrence as true || anything == true
Thus, if block is always entered and false is always returned.
Solution :
Change the if in your code :
if((line[i] != 'g' || line[i] != 'G') || (line[i+1] != 'e' || line[i+1] != 'E') || (line[i+2] != 't' || line[i+2] != 'T') || (line[i+3] != ' ' ))
To the following :
if((line[i] != 'g' && line[i] != 'G') || (line[i+1] != 'e' && line[i+1] != 'E') || (line[i+2] != 't' && line[i+2] != 'T') || (line[i+3] != ' ' ))
Here line[i] != 'g' && line[i] != 'G' gets evaluated to false as true && false == false and further expressions are checked till a true is encountered.
If no true is encountered then if() block is not entered
Further,
As #twalberg has suggested in the comment, it'd be much readable and understandable if you use your if statement as if( !strncasecmp(line, "get ", 3) ) by including the strings.h header file
Know more about strncasemp() function here : click
That comparison makes the code much harder to read. Use the function strncasecmp() (in either string.h or strings.h) instead:
if (strncasecmp(line, "get ", strlen("get ")) != 0) {
// ...
}
This will fix the logic error in that line -- your current comparison will always evaluate true. I would also suggest enabling more compiler warnings, as this is something that any compiler should catch.

Is there something wrong with my gets function? we haven't been though about fgets yet in class. only gets

for example when I type in a string "Hello", when I press 'a' it should print "There are 2 vowels." Instead, it says there are 0. I'm new to programming and this is the first language I am learning. Help?
/*
Student: Josiah Eleazar T. Regencia
Course: BSIT 1
Subject: SCS 101
Professor: Daniel B. Garcia
Problem definition:
Write a menu program that will count the vowels and consonants in the string
*/
#include <stdio.h> //printf and scanf functions
#include <string.h> //string functions
#include <stdlib.h>
#include <conio.h>
#define PROMPT "Type in a word, a phrase, or a sentence." //instucts the user
/*
Declaring the function for the user's menu
*/
void menu();
/*
Declaration of function needed to count the vowels in the string
*/
int vowel_count(char *stringInput); //declaring the function to count the vowels sounds
/*
Declaration of function needed to count the consonants in the stringn
*/
int consonant_count(char *stringInput); //declaring the functions to count the consonant sounds
/*
Declaring the function needed to convert the streeting to uppercase
*/
int uppercase(char *stringInput);
/*
Declaring the function needed to convert the streeting to uppercase
*/
int lowercase(char *stringInput);
int main () {
char userInput[100]; // the string the user inputs
char commandKey[1]; //this key is for the menu
char newInput[100]; //this is for the new input to user will put in
int stringLength; //to identify the length of the string
/*
Variables for counting the vowels and consonants
*/
int consonantCount;
printf("%s\n\n", PROMPT); //instucts the user
gets(userInput);
stringLength = strlen(userInput); //gets the length of the string
//fgets(userInput, 100, stdin);
/*if(stringLength > 0 && userInput[stringLength - 1] == '\n') {
userInput[stringLength - 1] ='\0';
}*/
menu(); //prints out the menu for the user to pick his options
/*
The loop will run what the user asks the program to run while at the same time also asking
what the programmer wants next
*/
while(*commandKey != 'X' || *commandKey != 'x') {
//int commandLength; //length of the command key
printf("Enter your menu selection: ");
gets(commandKey);
/*commandLength = strlen(commandKey);
fgets(commandKey, 100, stdin);
if(commandLength > 0 && commandKey[commandLength - 1] == '\n') {
commandKey[commandLength - 1] ='\0';
}*/
if(*commandKey == 'A' || *commandKey == 'a') {
int vowelCount;
vowelCount = vowel_count(userInput);
printf("There are %d vowels.\n\n", vowelCount);
}
if(*commandKey == 'B' || *commandKey == 'b') {
consonantCount = consonant_count(userInput);
printf("There are %d consonants.\n\n", consonantCount);
}
if(*commandKey == 'C' || *commandKey == 'c') {
/*
This condition simply converts the input string to all lowercase letters
*/
lowercase(userInput);
}
if(*commandKey == 'D' || *commandKey == 'd') {
/*
This condition simply converts the input string to all lowercase letters
*/
uppercase(userInput);
}
if(*commandKey == 'E' || *commandKey == 'e') {
/*
Prints the current string
if the string was converted in lowercase letters, the outcome would be all lowercase letters
if the string was converted in uppercase letters, the outcome would be all uppercase letters
*/
printf("%s\n\n", userInput);
}
if(*commandKey == 'F' || *commandKey == 'f') {
/*
When the user wants to test a new string, this is the condition for the user
to automatically ask of it
*/
printf("%s\n", PROMPT);
gets(newInput);
strcpy(userInput, newInput);
}
if(*commandKey == 'M' || *commandKey =='m') {
/*
In case the user forgets, this will serve as a reminder of the menu
*/
menu();
}
if(*commandKey == 'X' || *commandKey == 'x') {
printf("Goodbye!\n");
break;
}
}
}
//Function that displays the menu.
void menu() {
/*
These are the set of command keys given to the user
*/
printf("\n\n\n");
printf("PRESS:\n\n");
printf(" A - Count the number of vowels in the string.\n");
printf(" B - Count the number of consonants in the string.\n");
printf(" C - Convert the string to uppercase.\n");
printf(" D - Convert the string to lowecase.\n");
printf(" E - Display the current string.\n");
printf(" F - Enter another string.\n");
printf("\n");
printf(" M - Display this menu.\n");
printf(" X - Exit the program.\n");
printf("\n\n");
}
/*
Defining the function for the vowel counting
*/
int vowel_count(char *stringInput) {
if ( *stringInput == '\0')
return 0;
else
return vowel_count(stringInput + 1) + (*stringInput == 'a' || *stringInput == 'A')
+ (*stringInput == 'e' || *stringInput == 'E')
+ (*stringInput == 'i' || *stringInput == 'I')
+ (*stringInput == 'o' || *stringInput == 'O')
+ (*stringInput == 'u' || *stringInput == 'U');
}
/*
Defining the function for the vowel counting
*/
int consonant_count(char *stringInput) {
if (*stringInput == '\0')
return 0;
else
return consonant_count(stringInput + 1) + (*stringInput == 'b' || *stringInput == 'B')
+ (*stringInput == 'c' || *stringInput == 'C')
+ (*stringInput == 'd' || *stringInput == 'D')
+ (*stringInput == 'f' || *stringInput == 'F')
+ (*stringInput == 'g' || *stringInput == 'G')
+ (*stringInput == 'h' || *stringInput == 'H')
+ (*stringInput == 'j' || *stringInput == 'J')
+ (*stringInput == 'k' || *stringInput == 'K')
+ (*stringInput == 'l' || *stringInput == 'L')
+ (*stringInput == 'm' || *stringInput == 'M')
+ (*stringInput == 'n' || *stringInput == 'N')
+ (*stringInput == 'p' || *stringInput == 'P')
+ (*stringInput == 'q' || *stringInput == 'Q')
+ (*stringInput == 'r' || *stringInput == 'R')
+ (*stringInput == 's' || *stringInput == 'S')
+ (*stringInput == 't' || *stringInput == 'T')
+ (*stringInput == 'v' || *stringInput == 'V')
+ (*stringInput == 'w' || *stringInput == 'W')
+ (*stringInput == 'x' || *stringInput == 'X')
+ (*stringInput == 'y' || *stringInput == 'Y')
+ (*stringInput == 'z' || *stringInput == 'Z');
}
/*
Defining the function for the conversion of the string to all uppercase letters
*/
int uppercase(char *stringInput) {
while(*stringInput) {
*stringInput = toupper(*stringInput);
stringInput++;
}
}
/*
Defining the function for the conversion of the string to all uppercase letters
*/
int lowercase(char *stringInput) {
while(*stringInput) {
*stringInput = tolower(*stringInput);
stringInput++;
}
}
This loop will never stop:
while(*commandKey != 'X' || *commandKey != 'x')
A loop stops when its condition is false. For *commandKey != 'X' || *commandKey != 'x' to be false, it is logically equivalent for *commandKey == 'X' && *commandKey == 'x' to be true, which doesn't quite work. *commandKey can't be both 'X' and 'x'.
Instead, you want:
while(*commandKey != 'X' && *commandKey != 'x')
Which will stop when *commandKey is 'X' or 'x'.
Also, you never initialized commandKey, so you can't test it in the loop (using values of uninitialized variables is undefined behavior). And if you want to treat it as a string, you need to declare it such that it holds at least 2 characters, because the null character is needed:
char commandKey[2] = { 0 };
This will initialize commandKey to an empty string. Remember that gets() will null-terminate the string, so, even if your command is just one key, gets() will need at least 2 positions to fill - the character command and the null terminating byte. Alternatively, you can leave commandKey as is (provided that you initialize it), and use getchar() instead, which reads one single character.

What is wrong with my code that removes vowels from strings?

I'm new to programming and I've decided to do some simple programming exercises.
The challenge is to remove all vowels from a user inputted string.
I've already wrote the code and I don't know why it isn't working.
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
bool isVowel(char ch)
{
char charToBeTested = tolower(ch);
if(charToBeTested == 'a' || 'e' || 'i' || 'o' || 'u')
return true;
else
return false;
}
int main()
{
int i;
char formattedString[80];
printf("Enter a string: ");
scanf("%s", &formattedString);
for(i = 0; i < strlen(formattedString); i++)
{
if(isVowel(formattedString[i]) == true)
{
formattedString[i] = ' ';
}
}
printf("%s", formattedString);
return 0;
}
All it is supposed to do is check every character in the string and see if it's a vowel. If it's a vowel, replace the current character with a space. I will write the function to remove the spaces later.
All help is appreciated, sorry for being such a noob!
This code doesn't do what you think it does:
if (charToBeTested == 'a' || 'e' || 'i' || 'o' || 'u') {
...
}
C interprets this as
if ((charToBeTested == 'a') || 'e' || 'i' || 'o' || 'u') {
...
}
Here, the || operator is being applied directly to the character literals 'e', 'i', etc. Since C treats any nonzero value as "true," this statement always evaluates to true.
To fix this, try rewriting it like this:
if (charToBeTested == 'a' ||
charToBeTested == 'e' ||
charToBeTested == 'i' ||
charToBeTested == 'o' ||
charToBeTested == 'u') {
...
}
Alternatively, use a switch statement:
switch (charToBeTested) {
case 'a': case 'e': case 'i': case 'o': case 'u':
return true;
default:
return false;
}
Also, you might want to use tolower so that the testing is done case-insensitively.
Hope this helps!
This is incorrect:
if(charToBeTested == 'a' || 'e' || 'i' || 'o' || 'u')
correct is:
if(charToBeTested == 'a' || charToBeTested == 'e' || charToBeTested == 'i' || charToBeTested == 'o' || charToBeTested == 'u')
Or, you can create static table, like:
char vowels[0x100] = {
['a'] = 1,
['e'] = 1,
['i'] = 1,
['o'] = 1,
['u'] = 1,
};
And test by:
if(vowels[(unsigned char)charToBeTested])
You'll need to rewrite your isVowel function to something like:
bool isVowel(char ch)
{
char charToBeTested = tolower(ch);
if(charToBeTested == 'a') {
return true;
} else if(charToBeTested == 'e') {
return true;
} else if(charToBeTested == 'i') {
return true;
} else if(charToBeTested == 'o') {
return true;
} else if(charToBeTested == 'u') {
return true;
} else {
return false;
}
}
Alternatively, you can use a switch statement to do the same thing, like this:
bool isVowel(char ch)
{
char charToBeTested = tolower(ch);
switch(charToBeTested) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
default:
return false;
}
}
You need to test each alternative separately:
char c = tolower(ch);
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
Your original code is:
if (charToBeTested == 'a' || 'e' || 'i' || 'o' || 'u')
The compiler evaluates that as:
if ((charToBeTested == 'a') || true)
because 'e' is not zero and any expression which is not zero is true.
If it optimizes really thoroughly, can deduce that the whole expression will always be true, regardless of the value of charToBeTested, and hence it can reduce the entire function to return true (without ever needing to call tolower(). If it was a static function, it could even eliminate the function call altogether. Whether any compiler would actually be that aggressive is open to debate.
Just to add to everyones answer; as they say, you need to fix your testing criteria.
Also, don't forget to check for the Uppercase version too:
if (charToBeTested == 'a' ||
charToBeTested == 'e' ||
charToBeTested == 'i' ||
charToBeTested == 'o' ||
charToBeTested == 'u' ||
charToBeTested == 'A' ||
charToBeTested == 'E' ||
charToBeTested == 'I' ||
charToBeTested == 'O' ||
charToBeTested == 'U') {
...
}

Resources