C Programming - comparing a const char array to a user input [duplicate] - c

This question already has answers here:
Why is "a" != "a" in C?
(11 answers)
Closed 8 years ago.
I cannot figure out why this code is jumping straight to pattern 5. I've looked at it several times and I just don't see it. Any help would be greatly appreciated. I am guessing it has something to do with the way that I've initialized arrays and the way I am comparing them. I have tried using 'strcmp' and currently trying to compare direct array positions. Both of these have compiled successfully, but I just can't seem to get it to work.
char one[3][3];
const char *pattern[] = {"p1","p2","p3","p4","p5"};
printf("%s Commands are {'p1', 'p2', 'p3', 'p4', 'p5'\n", prompt);
printf("Enter your first pattern choice: ");
scanf("%2s",one[0]);
printf("Enter your second pattern choice: ");
scanf("%2s",one[1]);
printf("Enter your third choice: ");
scanf("%2s",one[2]);
for (int i = 0; i < 2; i++)
{
do{
if (one[i] == "p1")
{
printf("\n1.1");
patternOne();}
else if (one[i] == "p2")
{
printf("\n1.2");
patternTwo();}
else if (one[i] == "p3")
{
printf("\n1.3");
patternThree();}
else if (one[i] == "p4")
{
printf("\n1.4");
patternFour();}
else
{
printf("\n1.5");
patternFive();
}
}
while (i < 3);

For string comparison use strcmp() function from string.h.
You are not comparing strings in C style, so it is evaluating to else.
Your expected code will probably be:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char one[3][3];
const char *pattern[] = { "p1", "p2", "p3", "p4", "p5" };
printf("Enter your first pattern choice: ");
scanf("%2s", one[0]);
printf("Enter your second pattern choice: ");
scanf("%2s", one[1]);
printf("Enter your third choice: ");
scanf("%2s", one[2]);
for (int i = 0; i < 2; i++)
{
if (strcmp(one[i],"p1") == 0)
{
printf("\n1.1");
patternOne();
}
else if (strcmp(one[i], "p2") == 0)
{
printf("\n1.2");
patternTwo();
}
else if (strcmp(one[i], "p3") == 0)
{
printf("\n1.3");
patternThree();
}
else if (strcmp(one[i], "p4") == 0)
{
printf("\n1.4");
patternFour();
}
else if (strcmp(one[i], "p5") == 0)
{
printf("\n1.5");
patternFive();
}
else
{
printf("Unknown input.");
}
}
return(0);
}
Changes made:
Removed the inner do-while loop as i was incremented only by the
outer for loop. Since i was not incremented inside the do-while it
can cause infinite loop.
Added an else if cluse to handle p5 input and added a separate else
to indicate that un-expected output was encountered.
Replaced if else conditions with strcmp() equallent condition
and included string.h in the file.
Edit (to answer the comment):
If you want it to display all 3 results, change:
for (int i = 0; i < 2; i++)
To
for (int i = 0; i <= 2; i++)
Currently, for i < 2 it loops for i = {0, 1} and skips for i = 2 as condition fails. If you change condition to i <= 2, it will loop for i = {0, 1, 2}.

Related

Array goes of out of bounds without giving any errors

My professor asked me to make a Codebreaker game in C. (User is breaking the code by guessing original code. original code is given as a cmd-line arg.After every attempt;(b, w): the number of correct colors in the correct positions (b) and the number of colors that are part of the code but not in the correct positions (w) are printed as Feedback.)Only standard input and output is allowed. I got it working, but the arrays Secret_Code2 and guess2 goes out of bounds. It has some strange behaviours like changing int variables causes changes in arrays even they are independent. I'm aware that C does not check array bounds, is there any improvements that i can make?
Here is my code;
#include <stdio.h>
#define Max_Attempts 12
char *Sectret_CODE = NULL;
int main(int argc,char **argv)
{
//Definitions
printf("Available Colors: (B)lue (G)reen (O)range (P)urple (R)ed (Y)ellow\n\n");
//Getting input and validating
if(argc != 2)
{
fprintf(stderr,"Invalid input\n");
return 1;
}
Sectret_CODE = argv[1];
int i = Max_Attempts;
int Won = 0;
while (i > 0 && !Won)
{
int b = 0, w = 0, t=0;
char guess[4];
char Sectret_CODE2[4];
char guess2[4];
printf("No. guesses left: %i\n",i);
printf("Enter Your Guess: ");
scanf("%s",guess);
//printf("%s",guess);
for(int j = 0; j < 4; j++)
{
//printf("%s,%s\n",Sectret_CODE2,guess2);
if(Sectret_CODE[j] == guess[j])
{
b++;
}
else
{
Sectret_CODE2[t] = Sectret_CODE[j];
guess2[t] = guess[j];
t++;
printf("%s,%s,%i\n",Sectret_CODE2,guess2,t);
}
}
int s = t;
//printf("%i",t);
Sectret_CODE2[t] = '\0' ;
guess2[t] = '\0' ;
if(b == 4)
{
printf("You Won\n");
Won = 1;
return 0;
}
else
{
for(int j = 0; j < s; j++)
{
for(int k = 0; k < s;k++)
if(Sectret_CODE2[j] == guess2[k])
{
w++;
break;
}
}
}
printf("Feedback: %i,%i\n",b,w);
i--;
}
if(!Won)
{
printf("You Lose!\n");
}
}
You aren't allocating space for the terminating null character in your character arrays. Each array needs to hold up to 4 values, plus a terminating null character. So you need to declare them to hold 4+1 = 5 characters. Otherwise writing the null character can write past the end of the arrays.
Also, inside your loop, you are attempting to print those arrays using printf with %s before null-terminating them. You need to null-terminate them, at the proper point, before printing them with %s.

Interactive, restrictive, dynamic user input

I provided a link to a PDF of the assignment instructions.
[TL;DR]
Ask two questions: Are you afraid of the dark? Do you exercise?
Input: ā€˜Yā€™ for yes, ā€˜Nā€™ for no.
If input to second question is 'Y', One additional question: Minutes per day exercised?
Input: Integer > 0. However, if less than 10 per day, unqualified.
Output: Tells the user whether they can to enter ninja training or not.
What I'm having difficulties with:
Dynamically Allocating a Multidimensional String Array
I have only been coding for about a week, and I understand it's probably overkill for this assignment. With that being said, I got an idea while doing this assignment, and while I find it rather challenging to articulate my idea with words, here's an image that I feel captures what I am "visualizing."
Visual posted on https://www.eskimo.com/~scs/cclass/int/sx9b.html by Steve Summit
In this particular assignment, I think it's a waste of memory to keep the user's answer's. Nevertheless, what if I want to write a program that ask the user for a series of inputs, and at the end, correlate them, or make spurious correlations for teh lulz?
Spurious Correlations http://www.tylervigen.com/spurious-correlations by Tyler Vigen
A more practical reason, however, an MBTI Personality Type test? I don't know exactly all the possibilities, but they seem exciting.
That's what I want to achieve with dynamically allocating a multidimensional string array
Will update later
Original post follows...
The code works but some inputs are still allowed, namely any characters entered if the the first element is either Y or N.
Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char reference[][2] = { "Y", "N" };
char (*ptr_reference)[2] = reference;
int reference_minutes[1] = { 10 };
int *ptr_reference_minutes = reference_minutes;
char **user_input;
user_input = (char**)malloc(3 * sizeof(char*));
int i;
for (i = 0; i < 3; i++) {
user_input[i] = (char*)malloc(4 * sizeof(char));
}
if (!user_input) {
printf("Could not allocate memory!/n");
exit(1);
}
i = 0;
while (i == 0) {
printf("\nAre you afraid of the dark? Choose either [Y/N], and press enter when finished: \n");
fgets(user_input[i], 4, stdin);
user_input[i] = realloc(user_input[i], sizeof(char));
if (strncmp(user_input[i], *ptr_reference, 1) == 0) {
printf("\nPatience, Young Grasshoper! You are not ready to become a ninja.");
i = 3;
break;
} else if (strncmp(user_input[i], *(ptr_reference + 1), 1) == 0) {
i++;
break;
} else {
printf("\nPlease enter Y for yes or N for no.\n\n");
continue;
}
}
while (i == 1) {
printf("\nDo you exercise? Input [Y/N], and press enter when finished: \n");
fgets(user_input[i], 4, stdin);
if (strncmp(user_input[i], *ptr_reference, 1) == 0) {
i++;
break;
} else if (strncmp(user_input[i], *(ptr_reference + 1), 1) == 0) {
printf("\nDo you even lift, Bro?");
i = 3;
break;
} else {
printf("\nPlease enter Y for yes or N for no.\n\n");
continue;
}
}
while (i == 2) {
int sscanf_result, answer;
printf("\nHow many minutes a day do you exercise? Type an integer greater than 9 and press enter when finished.\n");
fgets(user_input[i], 4, stdin);
sscanf_result = sscanf(user_input[i], "%d", &answer);
if ((sscanf_result == 0) | (sscanf_result == EOF)) {
/* either a non-integer entered or an end-of-line */
printf ("\nYou have to enter an integer!\n");
i = 2;
continue;
} else if (answer < *ptr_reference_minutes) {
printf("\nCome on! You kids are soft! You lack discipline!\n");
i = 3;
break;
} else {
printf("\nYou are a good fit for ninja training.\n");
for (i = 0; i < 3; i++) {
free(user_input[i]);
}
free(user_input);
user_input = NULL;
break;
}
}
return 0;
}
Ok, I could have a look at your program. The problem is not really in allocation but is indeed in string management. In C a string is a null terminated char array (please copy this 100 times...).
When you read a line with fgets, you get the new line character (\n) in your buffer, so if user types Y Enter you get {'Y', '\n', '\0', undeterminated_char }. The following realloc is then plain wrong:
it is likely to be a noop: the compiler shall only give you a buffer at least as large as your requirement. As 4 > 1, it can (and my implementation did) give the original buffer unchanged
you are not allowed to use anything past what you have required, and in particular, you shall not assume that there is a null!
So if you insist in doing a string comparison, you should only ensure that the second char is null: user_input[i][2] = '\0';
But IMHO what is required here is just:
if (user_input[i][0] == 'Y') {
...
That is not all. You try to do a great job in input processing, but just forgot one detail: if a line is longer than the declared size, fgets fills its buffer and leaves the remaining part of the line available for next read.
What follows is only my advice:
You have tried to use everything you know (and probably things you do not fully master...) into a single and simple program. Don't. Keep each program as simple as possible (Keep It Stupid Simple is a general good practice...), and trust your learner to give you other assignments for other patterns. So here you should:
read a line until you find the \n (it might require several fgets)
test the first character of the buffer to be 'Y' or 'N'
test the second one to '\0'
As it is a common requirement in real world, and only after your program works, you could considere:
ignoring initial blank characters
accept lower case as upper case
accept any character after first one (in order to accept Yes and No)
Last advice if nice coding matters for you: once your program works correctly, you should considere posting it in Code Review to get interesting comments on it.
#Serge Ballesta #Serga Ballesta Thank you kindly for your feedback. It was extremly helpful. After following your advice, I was able to write a better program, although, I'm not sure if I was successful in "Keep It Simple, Stupid."
I still can't figure out how to restrict characters after 'Y' or 'N', i.e., Nnb or Nq is accepted as N and goes through to the second question.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void) {
char *user_input = NULL;
user_input = (char*)malloc(3*sizeof(char));
int sscanf_result, answer;
int i;
while (!*user_input)
{
printf("\nAre you afraid of the dark? \n\nInput Specifications: Please type 'Y' to indicate yes, or 'N' to indicate no, and then press the 'Enter' or 'return' key when finished.\n\n");
i = 0;
fgets(user_input, sizeof(user_input), stdin);
/* trim off last character */
user_input[strlen(user_input)-1] = '\0';
if (user_input[i] == 'Y')
{
printf("\nFear of the dark? Fear those who lurk in the dark, my friend. Ninjas! You may not train as a ninja!");
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
exit(0);
}
else if (user_input[i] == 'N')
{
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
printf("\nDo you exercise?\n\nInput Specifications: Please type 'Y' to indicate yes, or 'N' to indicate no, and then press the 'Enter' or 'return' key when finished.\n\n");
i = 0;
fgets(user_input, sizeof(user_input), stdin);
user_input[strlen(user_input)-1] = '\0';
if (user_input[i] == 'N')
{
printf("\nDo you even lift, Bro?\n");
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
exit(0);
}
else if (user_input[i] == 'Y')
{
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
printf("\nHow many minutes a day do you exercise?\n\nInput Specifications: Please type a positive integer and press the 'Enter' or 'return' key when finished.\n\n");
i = 0;
fgets(user_input, sizeof(user_input), stdin);
user_input[strlen(user_input)-1] = '\0';
sscanf_result = sscanf(user_input, "%d", &answer);
if ((sscanf_result == 0) | (sscanf_result == EOF))
{
/* either a non-integer entered or an end-of-line */
printf ("\nPlease type a positive integer and then press the 'Enter' or 'return' key when finished.\n");
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
continue;
}
if (answer < 10)
{
printf("\nCome on! You kids are soft! You lack discipline!\n");
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
exit(0);
}
else
{
printf("\nYou may begin training as a ninja!\n");
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
exit(0);
}
}
else
{
printf("\nInput Error: Please carefully read the input specifications that are provided after each question prompt and then try again.\n");
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
continue;
}
}
else
{
printf("\nInput Error: Please carefully read the input specifications that are provided after each question prompt and then try again.\n");
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
continue;
}
}
return 0;
}

Sorting strings alphabetically in C language

I made a program that asks the user to enter a name if they select option 2 and it stores that name in the string, if the user selects option 3 then it will display that name. Now for option 4 it needs to alphabetize the names in order, so when i select option 3 again to view the names it would show them in alphabetical order. My friend told me to use strcpy(), and i attempted it but not too successfully.
This is my code:
//This is my code:
#include<stdio.h>
#include<string.h>
int main() {
int i = 0;
int j = 0;
while (1) {
int num;
char name[500][100],t[100];
printf("\nPress 1 to see author info\n");
printf("Press 2 to enter a name\n");
printf("Press 3 to view names\n");
printf("Press 4 to alphabatize names\n");
scanf("%d", &num);
char arr[100];
if (num == 1)
{
printf("----------------\n");
printf("name\n");
printf("132\n");
printf("----------------\n");
}
if (num == 2)
{
printf("Enter the name (no spaces)\n");
scanf("%s", arr);
strcpy(name[i], arr);
i++;
}
if (num == 3)
{
printf("\n******************************");
for (int j = 0; j<i; j++)
{
printf("\n%s\n", &name[j]);
}
printf("\n\n\n******************************");
}
if (num == 4)
{
for (i = 1; i < j; i++) {
for (j = 1; j < i; j++) {
if (strcmp(name[j - 1], name[j]) > 0) {
strcpy(t, name[j - 1]);
strcpy(name[j - 1], name[j]);
strcpy(name[j], t);
}
}
}
;
}
return(0)
system("pause");
}
If Barmar doesn't want to make the comment an answer:
As noted: the i you use in the outer loop is the total, you cannot use it, you need a fresh one, say k. Sorted alphabetically gives:
int k;
if (num == 4) {
for (j = 0; j < i; j++) {
for (k = 0; k < i - j - 1; k++) {
if (strcmp(name[k], name[k + 1]) > 0) {
strcpy(t, name[k]);
strcpy(name[k], name[k+1]);
strcpy(name[k+1], t);
}
}
}
}
I used a slightly different approach for the bubble sort, that's how I learned it, hope you can make sense of it.
Note: copying the full strings is not the best way to do it but I don't know if you already learned about pointers.
Modified your code. It seems that for this situation, switch case would be prettier and that your loop will never end. With what #Barmar said, your loop has a return 0; therefore terminates prematurely. I have changed some elements of your codes too as some of them are suited to be undisturbed etc. etc.
Change List
Besides the implementation of switch case
Name and position of char arrays. For t[100], since it is a temporary object/variable I moved it into case (4) (Refer to line 63
in the modified code) so that the creation happens on demand instead
of the original code where creation is made early. Renamed t to temp.
As for arr, I've renamed it so that it is clearer (nameIn to indicate
name Input)
Name of num. To make it easier to understand the code, I've set it to nameCount, to indicate the number of name, or the size.
Restructured loops so that their counters do not modifiy nameCount by any means and only use it as a mean of comparison.
Added exit condition for the loop to terminate, -1 as well as a default case should invalid input is provided. (Does not check for
alphabet input)
Modified Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int nameCount = 0, num = 0;
while (num != -1)
{
char nameIn[100];
char name[100][100];
printf("\nPress 1 to see author info\n");
printf("Press 2 to enter a name\n");
printf("Press 3 to view names\n");
printf("Press 4 to alphabatize names\n");
scanf("%d", &num);
switch(num)
{
case (1):
{
printf("----------------\n");
printf("name\n");
printf("132\n");
printf("----------------\n");
break;
}
case (2):
{
printf("Enter the name (no spaces)\n");
scanf("%s", nameIn);
strcpy(name[nameCount], nameIn);
nameCount++;
break;
}
case (3):
{
printf("\n******************************");
for (int ctr = 0; ctr<nameCount; ctr++)
{
printf("\n%s\n", &name[ctr]);
}
printf("\n\n\n******************************");
break;
}
case (4):
{
for (int ctrLv1 = 0; ctrLv1 < nameCount-1; ctrLv1++)
{
printf("\nhere here");
for (int ctrLv2 = ctrLv1+1; ctrLv2 < nameCount; ctrLv2++)
{
printf("\nif fail?\n\n\n");
if (strcmp(name[ctrLv1], name[ctrLv2]) > 0)
{
char temp[100] = "";
strcpy(temp, name[ctrLv1]);
strcpy(name[ctrLv1], name[ctrLv2]);
strcpy(name[ctrLv2], temp);
}
}
}
break;
}
case (-1):
{
printf("\nExiting...\n");
break;
}
default:
{
printf("Invalid input");
break;
}
}
}
return(0);
}

delete repetition in strings

i want to write code in c language to delete any character in string s1 which matches any character in the string s2 . using only for loops. that is my trial has failed -_- .
for example if s1="ahmed" and s2="omnia" should edit s1 to >> s1="hed"
#include <stdio.h>
#include <stdlib.h>
int i,j;
int k;
int counter=0;
int main()
{
char s1[100];
char s2[10];
char temp[100];
printf("\n enter string 1: ");
scanf("%s",s1);
printf("\n enter string 2: ");
scanf("%s",s2);
printf("\n%s",s1);
printf("\n%s",s2);
for(j=0;j<9;j++)
{
for(i=0;i<9;i++)
{
if(s1[i]!=s2[j]&&s1[i]!='\0')
{
temp[counter++]=s1[i]; //add unique items to temp
k=counter; //size
temp[counter]='\0';
}
}
}
for(i=0;i<k;i++)
{
s1[i]=temp[i];
}
printf("\nstring 1 after delete : ");
printf("%s",s1);
return 0;
}
how can i compare one item with nested items then achieve a condition ??
Why are you including the null character statements inside the if statement?
Try these two statements after the two for loops, like this. And please indent your code.
for(j=0;j<strlen(s1);j++) //Why is it 9 in your code? It should be the respective lengths
{
for(i=0;i<strlen(s2);i++)
{
if(s1[i]!=s2[j]&&s1[i]!='\0')
{
temp[counter++]=s1[i];
}
}
}
k=counter;
temp[counter]='\0';
and include:#include<string.h>
I don't see any coding errors here, only your logic is flawed.
This should work
for (j = 0; j < 9; j++)
{
for (i = 0; i < 9; i++)
{
if (s1[j] == s2[i] && s1[i] != '\0')
{
break;
}
else if (i == strlen(s2))
{
temp[counter++] = s1[j];
}
}
}
temp[counter] = '\0';
for (i = 0; i < counter; i++)
{
s1[i] = temp[i];
}
printf("\nstring 1 after delete : ");
printf("%s", s1);
In your original code you kept reading the original string from the beginning, instead of advancing the iterator each time.
So in the first iteration you compared 'ahmed' against 'omnia' which is fine.
In the second iteration though, you compared 'ahmed' against 'omnia', instead of 'hmed' against 'omnia', and that's why you got a large repetition of the original string in your output.
Also, I'd memset the memory of s1 and s2 first to 0.

scanf resulting in infinite loop [duplicate]

This question already has answers here:
Why is scanf() causing infinite loop in this code?
(16 answers)
Closed 9 years ago.
I had this problem before but went around it using other operator. But the same operator can't be used here I think (the getche();). Anyway this works well and good but if I input a letter it goes into an infinite loop.
printf("Enter the number of the passenger you wish to edit.");
scanf("%d", &userchoice);
do
{
if(userchoice <= count || userchoice <= 1)
{
flag = 0;
}
else
{
printf("Please enter a valid input!");
scanf("%d", &userchoice);
flag = 1;
}
} while (flag == 1);
You should see this answer :
https://stackoverflow.com/a/1716066/2263879
The problem is with your scanf.
Yes , it will go into .
Since you are checking for userchoice<=1 , letter ascii value would be compared which will always be false and flag will always be 1
P.S: I am assuming count is pretty small number here , since you have not provided the value of it.
Do you mean userchoice between 1 and count, then the first if is incorrect.
This code works, when you want to test in-between 1 and count.
#include <stdio.h>
#include <ctype.h>
int main(int argc, char *argv[]) {
signed int count = 5;
signed int flag = 1;
signed int userchoice = 0;
printf("Enter the number of the passenger you wish to edit:");
scanf("%d", &userchoice);
do {
if(userchoice <= count && userchoice >= 1) {
flag = 0;
} else {
char c = '0';
if (scanf("%d", &userchoice) == 0) {
printf("Please enter a valid input!\n");
do {
c = getchar();
}
while (!isdigit(c));
ungetc(c, stdin);
}
}
} while (flag == 1);
printf("Done!");
}
Output:
a is not valid, because it is not a digit, 6 is bigger than count. 3 is possible and gets accepted.
Enter the number of the passenger you wish to edit:a
Please enter a valid input!
6
3
Done!

Resources