I want to reference the input of name throughout the code I am writing, but for some reason after I use it successfully in the first printf(), the second printf() does not print the name.
int main()
{
char name[50];
char q1[1];
printf( " What is your name?\n");
scanf("%s", name);
printf( " Hi %s, Do you want to have some fun? [Y/N]\n",name);
scanf("%s",q1);
if(strcmp(q1,"Y") == 0||strcmp(q1,"y")==0)
{
printf("Awesome, let's play!\n");
}
else
{
printf("Fine"); goto endgame;
}
printf( "So %s, it's time to get started\n", name);
endgame:
getchar();
return 0;
}
The output for the entry 'Nick' is:
Hi Nick, do you want to have some fun? Awesome let's play So ,
let's get started
I would expect it to say:
So Nick, let's get started.
but for some reason char name is blank after it is used correctly the first time.
The problem, (as I assumed correctly) is with char q1[1]; and then using it like
scanf("%s",q1);
It is causing memory boundary overrun, because, a one-char array is not sufficient to hold a string of having only one element, as it lacks the space for the null-terminator required for the string. This invokes undefined behaviour.
Instead,
change char q1[1]; to char q1;
change scanf("%s",q1); to scanf(" %c", &q1);
change if(strcmp(q1,"Y") == 0||strcmp(q1,"y")==0) to if((q1 =='Y') || q1 == 'y')
That said, as a note,
The recommended signature of main() is int main(void).
To avoid the possibility of buffer overflow by longer input(s), it's better to limit the length of the input with scanf() by writing like
scanf("%49s", name);
Expand the size of your q1 buffer. scanf("%s", q1) doesn't have enough room to store the input. Remember that C uses a null character '\0' to terminate strings. If you don't account for that, the buffer could overrun into other memory causing undefined behavior. In this instance, it's probably overwriting memory allocated to name, so name ends up pointing to "\0ick". This causes printf(%s), which looks for '\0' to know when to stop printing, to think that the string is shorter than it really is.
The code works perfectly if you expand the buffer:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char name[50];
char q1[50];
printf( " What is your name?\n");
scanf("%49s", name);
printf( " Hi %s, Do you want to have some fun? [Y/N]\n",name);
scanf("%49s",q1);
if(strcmp(q1,"Y") == 0||strcmp(q1,"y")==0)
{
printf("Awesome, let's play!\n");
}
else
{
printf("Fine");
}
printf( "So %s, it's time to get started\n", name);
getchar();
return 0;
}
Output:
What is your name?
Nick
Hi Nick, Do you want to have some fun? [Y/N]
y
Awesome, let's play!
So Nick, it's time to get started
Note that I've added the qualifier %49s to avoid buffer overruns like this.
You could also circumvent the need for another string entirely by changing char q1[50] and scanf("%49s") to simply char q1 and scanf("%c%*c", &q1) (note the "address of" operator because q1 is no longer a pointer).
You'll probably even get a performance gain from this (albeit small), because strings are notorious memory hoggers. Comparing a single character is usually preferred over comparing strings.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char name[50];
char q1;
printf( " What is your name?\n");
scanf("%49s%*c", name);
printf( " Hi %s, Do you want to have some fun? [Y/N]\n",name);
scanf("%c%*c",&q1);
if(q1 == 'Y' || q1 == 'y')
{
printf("Awesome, let's play!\n");
}
else
{
printf("Fine");
}
printf( "So %s, it's time to get started\n", name);
getchar();
return 0;
}
if(q1 == 'Y' || q1 == 'y')
{
printf("Awesome, let's play!\n");
}
else
{
printf("Fine");
}
printf( "So %s, it's time to get started\n", name);
getchar();
return 0;
}
If you go this route, you have to ignore the enter key using the format specifier %*c because pressing enter sends a key to the stream as well.
Related
I'm new to C, and I was trying to create a password system with 2 questions. 1. "What is your password?" I prompted the user to answer and recorded the argument. Any input was assigned to the variable. 2."Are you sure? Do you want this password? Enter Yes or No." It would decide whether to use the answer or discard it. Everything was working smoothly until this part. I couldn't type Yes or No. It automatically assumed that I had typed yes and saved it. Can somebody please give me some advice?
#include <stdio.h>
int
main ()
{
char password;
printf ("Hello User.");
printf ("Please type in your password:");
scanf ("%d", & password);
char answer;
printf ("\nAre you sure? Do you want this password? Enter Yes or No: \n");
scanf ("%c", answer);
printf ("\nAnswer is %c");
if (answer == 'Yes')
printf ("Confirmed.");
else (answer == 'No');
printf ("OK. Thank you.");
password = 0;
return 0;
}
As noted in the comments, you likely didn't intend to store a password in a single character. Nor did you likely intend to scanf the password as an integer using, which is what you're saying with %d.
You may want to use getline instead to read an entire line, and store it in password if you declare it as char array.
Let's say you gave it room for 100 chars.
char password[100];
You might read your password in with:
getline(password, 100, stdin);
You can do the same for the second question, but should always use strcmp to compare strings in C. When the two strings are equal, the return value is 0. Be careful as this is opposite of the way that "true" is usually represented by integers in C.
if (strcmp(response, "yes") == 0) {
...
}
Hopefully these tips will point you in the right direction.
Research and study the functions and syntax.
#include <stdio.h>
#include <string.h>
//function: Clears password
void clearPassword(char p[])
{
for(int i = strlen( p ); i>=0; i--)
{
p[i]='\0';
}
}
int main ()
{
char password[101]; //C version of a String
char line[100]; //C version of a String
char answer;
printf ("Hello User.");
printf ("Please type in your password: ");
fgets(line, sizeof(line), stdin); // read input
sscanf(line, "%s", &password); // store password
printf ("\nAre you sure? Do you want this password? Enter Y or N: \n");
fgets(line, sizeof(line), stdin); //read input
sscanf(line, "%c", &answer); // store answer
printf ("\nAnswer is %c \n", answer); // print answer
if (answer == 'Y') //
printf ("Confirmed.");
else
{
clearPassword(password);
printf ("OK. Thank you.");
}
return 0;
}
The console will not do anything after the user has entered a string.
I have got the code to work using char string="enteraword" and taking out the whole printf and scanf function, however I need the code to work with a scanf function.
#include <stdio.h>
#include <string.h>
int main()
{
char* string;
printf("Enter a word: ");
scanf("%s", string);
char c=string[1];
printf("The second letter in %s is %c", string, c);
return 0;
}
This code has undefined behavior, you're passing an uninitialized pointer to scanf(), asking it to store a string there.
Also, remember that %s will stop at whitespace, so it's very unclear what "terms" should mean here.
Try e.g.:
char string[1024];
if(scanf("%1023s", string) == 1 && string[0] != '\0')
{
const char c = string[1];
printf("The second letter of '%s' is '%c'\n", string, c);
}
I am trying to learn to program in C but am having trouble with manipulating strings as C treats strings as arrays.
My aim was to make a program that stores the users first name and surname.
Here is my progress:
#include <stdio.h>
int main(int argc, const char * argv[]) {
//defining the variables
char first_name[100];
char surname[100];
char ch[2];
// Asking for the first name and storing it
printf("What's your first name?\n");
scanf("%s", first_name);
// Prints the first name
printf("Hey %s!\n",first_name);
//Asks the user if they want to store their surname
printf("Would you like to tell me your second name? This is optional so type 'Y' for yes and 'N' for no.\n");
scanf("%s", ch);
//validate if they want to store it or not
if (ch == "Y"){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
return (0);
}
However, with this code, I get an error because my IDE(xCode) tells me to use the strcmp function. I then edited the code to become this:
if (strcmp(ch, "Y")){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
However variable ch is not a literal and so is not comparable.
Sidenote
I did try to compare two literals too, just to see how it works:
char *hello = "Hello";
char *Bye = "Bye";
if (strcmp(hello, Bye)){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
But even this gave an error:
Implicitly declaring library function 'strcmp' with type 'int (const *char, const *char)'
I believe I am not able to do this due to my lack of experience so it would be much appreciated if you could help me understand what I'm doing wrong and how I can fix the problem.
You need to include the appropriate header:
#include <string.h>
Also note that your desired logic probably calls for:
if (!strcmp(hello, Bye))
Instead of:
if (strcmp(hello, Bye))
Since strcmp returns 0 in case of equality.
There are several issues you should correct concerning how you handle input with scanf. First always, always validate the number of successful conversions you expect by checking the return for scanf. Next, as mentioned in the comment, there is NO need to include <string.h> in your code to make a one-letter comparison. Use a character comparison instead of a string comparison. Lastly, always limit your input to the number of characters available (plus the nul-terminating character.
Putting the bits together, you could do something like the following:
#include <stdio.h>
#define MAXN 100
int main (void) {
char first_name[MAXN] = "", surname[MAXN] = "";
int ch;
printf ("What's your first name?: ");
if (scanf ("%99[^\n]%*c", first_name) != 1) {
fprintf (stderr, "error: invalid input - first name.\n");
return 1;
}
printf ("Hey %s!\n", first_name);
printf("Enter surname name? optional (Y/N) ");
if (scanf("%c%*c", (char *)&ch) != 1) {
fprintf (stderr, "error: invalid input - Y/N\n");
return 1;
}
if (ch != 'y' && ch != 'Y') /* handle upper/lower case response */
return 1;
printf ("Enter your surname?: ");
if (scanf (" %99[^\n]%*c", surname) != 1) {
fprintf (stderr, "error: invalid input - surname\n");
return 1;
}
printf ("\nYour whole name is : %s %s\n", first_name, surname);
return 0;
}
Example Use/Output
$ ./bin/firstlast
What's your first name?: David
Hey David!
Enter surname name? optional (Y/N) Y
Enter your surname?: Rankin
Your whole name is : David Rankin
Look it over and let me know if you have any questions.
There are two problems here. Firstly you need to see what value is returned by the strcmp and secondly you must use the approprate hedder.
You must use:
#include <string.h>
Secondly, you must edit your if-else statement so it is like this:
if (strcmp(ch, "Y") == 0){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
We do this because the strcmp function returns a negative value if ch is smaller than "Y", or a positive value if it is greater than "Y" and 0 if both strings are equal.
Ok, thats half of my code, but i have problem and i cant fix it. For example i need to pick choice 2 it is adding something to file, i enter[ name, surname, date, gender ] press enter and program shows like menu again(2.Add to file) but this time automatically picks 2 choice and i need to write data another time and it happens all the time when picking choice 2. Please help me find solution of this problem.
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#define N 15
struct date
{ int da_year;
int da_month;
int da_day;
};
struct studenti
{
int Nr;
char name[25];
char surname[25];
struct date dzd;
char dzimums;
}students[N] ;
int main()
{
sakums:
// FILE *fails_st;
char line[100];
char *ptk; char * end; int i;int sorted;
int g=0,ch,count=0;
int n;
int choice;
FILE *fails_st = fopen("studenti.txt", "r+");
/* errors ja neizdodas atveert failu */
if (fails_st == NULL)
{
printf("Error opening file!\n");
exit(1);
}
printf("\n2.Add to file");
scanf("%d",&choice);
if(choice==2){
/* write in file */
for (n=0; n<1; n++)
{
printf("%d. Ievadiet: vards, uzvards, datums, dzimums >", n+1);
scanf("%s",&students[n].name);
scanf("%s",&students[n].surname);
scanf("%d.%d.%d", &students[n].dzd.da_day, &students[n].dzd.da_month, &students[n].dzd.da_year);
scanf("%c",&students[n].dzimums);
}
fseek(fails_st, 0, SEEK_END);
for (i=0; i<n; i++)
fprintf(fails_st, " %d. %s %s %d.%d.%d %c\n", N+1, students[i].name,
students[i].surname, students[i].dzd.da_day,
students[i].dzd.da_month, students[i].dzd.da_year,
students[i].dzimums);
fclose(fails_st);
goto sakums;
}
getche();
return 0;
}
Your problem is likely that scanf happily does nothing if the format string that is its first parameter doesn't match the available input. That means it won't change the value of choice, so it will still be 2.
The cause of this is probably that what you input doesn't match your format strings. You can detect when this happens by checking the return value of scanf - it will return the number of variables written to, basically. If that is less than the number of format specifiers in your format string, something went wrong.
At that point, you probably want to consume all the available input (maybe something like int c; do { c = getchar(); } while (c != '\n' && c != EOF); for a simple program like yours) and then prompt the user again.
In particular, I believe your scanf("%c", ...) is likely the culprit: %c, unlike most scanf specifiers, will not ignore leading whitespace, but accept any character. So if you typed in "firstname lastname 1980.6.11 f", for example, the previous scanf call will just have consumed "6.11.1980", leaving " f" in the input buffer (note the space). Then the scanf with %c will read the space into the gender field, and leave the "f" in the input buffer. On the next go around, scanf("%d",&choice); will not do anything because "f" is not a valid number, choice will remain 2 and the "f" will get read as the first name on the next student entry, further confusing matters...
The solution is, I believe, to use scanf(" %c", ...); to explicitly consume leading whitespace.
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(void)
{
int menuswitch=1;
int amountofstudents;
int fname[50];
int lname[50];
int grade[50];
int i;
char studentinfo[100];
printf("Enter Amount of Students: ");
scanf("%d", &amountofstudents);
for (i=0;i<amountofstudents;i++)
{
gets(studentinfo);
strcpy(fname[i], strtok(studentinfo, " "));
strcpy(lname[i], strtok(NULL, " "));
strcpy(grade[i], strtok(NULL, " "));
}
Alright need a little using strtok. I am trying to store pieces of an input string to sort later. I was thinking of using strtok to break the string then placing each piece in the corresponding array. Yet, every time I try I get an error in Visual Studios saying Access Violation. Thanks for the help ahead of time
The error is
First-chance exception at 0x5120F7B3 (msvcr110d.dll) in Lab 2.exe: 0xC0000005: Access violation reading location 0x00000000.
Unhandled exception at 0x5120F7B3 (msvcr110d.dll) in Lab 2.exe: 0xC0000005: Access violation reading location 0x00000000.
The input would be
FirstName Lastname 80(Grade)
One major problem is that you try to copy into integer values and not strings. Change the
integer arrays to arrays of strings:
...
char fname[50][100];
char lname[50][100];
char grade[50][100];
...
You also have a problem with the gets function (besides it being obseleted and should not be used), namely that the previous scanf doesn't remove the newline from the input buffer so the first gets call will see this empty newline and give you an empty line (which you do not check for).
This is simply solved by telling scanf to discard trailing whitespace by adding a space in the format string after the "%d":
scanf("%d ", &amountofstudents);
/* ^ */
/* | */
/* Note space */
Instead of gets, you should be using fgets:
fgets(studentinfo, sizeof(studentinfo), stdin);
And finally, always check for errors!
a potential issue is the scanf/gets combo. use instead fgets() and convert when appropriate to integer using atoi() it is also good to do a sanity check on what is returned from strtok (it is never good to assume anything about input)
char* token = strtok(studentinfo, " ");
if ( strlen(token) < sizeof(fname[i]) )
{
strcpy(fname[i], token);
...
you have also declared your strings as integer arrays, they should be char
e.g. char fname[50];
The problem you have is that you have declared three variables (fname, lname, and grade) as char[] (arrays) (well, that is the type you meant to use), but you want to prompt for and keep around a bunch of students information. And you later try to copy from strtok() into what you want to be a char[], but since you dereferenced fname[i] (lname[i], grade[i]), they are of type char, rather than char[].
You will need stdlib.h for exit,
#include <stdio.h>
#include <stdlib.h> //for exit
#include <string.h>
//#include <math.h> //you don't need this, yet
#define STUDLIMIT (100)
You can either create an array of fname[], lname[], grade[], (see here: http://www.cs.swarthmore.edu/~newhall/unixhelp/C_arrays.html),
int main(void)
{
//int menuswitch=1; //you aren't using this
int amountofstudents;
char studentinfo[100];
char fname[STUDLIMIT][50];
char lname[STUDLIMIT][50];
char grade[STUDLIMIT][50];
int ndx;
printf("Enter Amount of Students: ");
if( (fscanf(stdin,"%d ", &amountofstudents)<=0)
|| (amountofstudents<1) || (amountofstudents>STUDLIMIT) )
{
printf("need %d to %d studends\n",1,STUDLIMIT); exit(0);
}
for (ndx=0;ndx<amountofstudents;ndx++)
{
printf("Student: "); fflush(stdout);
fgets(studentinfo,sizeof(studentinfo),stdin);
strcpy(fname[ndx], strtok(studentinfo, " "));
strcpy(lname[ndx], strtok(NULL, " "));
strcpy(grade[ndx], strtok(NULL, " "));
}
}
Or you can create a struct(ure) to hold the entered student information, and instantiate an array of these student records, one for each student you enter and store,
typedef struct student
{
char fname[50];
char lname[50];
char grade[50];
} StudentObj;
int StudentCopy(StudentObj*sp,char*fname,char*lname,char*grade)
{
if(!sp || !fname || !lname || !grade ) return -1;
strcpy(sp->fname, fname);
strcpy(sp->fname, lname);
strcpy(sp->fname, grade);
}
StudentObj students[STUDLIMIT];
int main(void)
{
//int menuswitch=1; //you aren't using this
int amountofstudents;
char studentinfo[100];
char fname[50];
char lname[50];
char grade[50];
int ndx;
printf("Enter Amount of Students: ");
if( (fscanf(stdin,"%d ",&amountofstudents)<=0)
|| (amountofstudents<1) || (amountofstudents>STUDLIMIT) )
{
printf("need %d to %d studends\n",1,STUDLIMIT); exit(0);
}
for (ndx=0;ndx<amountofstudents;ndx++)
{
printf("Student: "); fflush(stdout);
fgets(studentinfo,sizeof(studentinfo),stdin);
strcpy(fname, strtok(studentinfo, " "));
strcpy(lname, strtok(NULL, " "));
strcpy(grade, strtok(NULL, " \n\r"));
StudentCopy(&(students[ndx]),fname,lname,grade);
}
}