How to enter and scan multiple chars in c - c

I want to enter multiple printfs but i dont get opportunity to enter.
I can enter only 1, but after that it just ends the programme.I tried with do while but it didnt work
int main()
{
int number;
char username[30]="";
char fullName[30]="";
char password[30]="";
printf("Do you want to log in(1) or register (2)? \n");
scanf("%d",&number);
if (number==2)
{
printf("username : ");
scanf("%s",&username);
printf("Full name : ");
scanf("%s",&fullName);
printf("Password : ");
scanf("%s",&password);
printf("Repeat password : ");
scanf("%s",&password);
}
return 0;
}

Read full lines using fgets() into a suitably large buffer, then parse that.
Note that %s will stop at the first blank character, so a full name of "Mr X" will leave "X" in the input buffer, grabbing that for the password and so on. It's really not a robust way of getting input.

I can enter only 1, but after that it just ends the programme.
Of course, as the code has if (number==2) #Scadge
If you enter "2", consider the following:
scanf("%s",&fullname); will not save spaces or other white-spaces into fullname. Entering a full name like "John Doe" will save "John" into fullname and "Doe" into password.
Avoid using scanf().
Rather than use scanf() to read user input, read user input with fgets(). This is a fine opportunity for helper functions that can handle various input issues.
int read_int(const char *prompt) {
if (prompt) fputs(prompt, stdout);
fflush(stdout); // insure output is written before asking for input
char buffer[40];
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
return NULL;
}
int i;
if (sscanf(buffer, "%d", &i) == 1) {
return i;
}
// TBD - what should code do if invalid data entered. Try again?
}
char *read_line(char *dest, sizeof size, const char *prompt) {
if (prompt) fputs(prompt, stdout);
fflush(stdout); // insure output is written before asking for input
char buffer[size * 2 + 1]; // form buffer at _least 1 larger for \n
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
return NULL;
}
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') buffer[--len] = '\0';
if (len >= size) {
// input too big - how do you want to handle this?
TBD_Code();
}
return strcpy(dest, buffer);
}
Now use these 2 helper functions for clean user input
// printf("Do you want to log in(1) or register (2)? \n");
// scanf("%d",&number);
number = read_int("Do you want to log in(1) or register (2)? \n");
...
// printf("username : ");
// scanf("%s",&username);
read_line(username, sizeof username, "username : ");
// printf("Full name : ");
// scanf("%s",&fullName);
read_line(fullName, sizeof fullName, "fullName : ");
Additional code could be added to check for end-of-file, extremely long lines, int range testing, etc.

Use c library function fgets().
#include <stdio.h>
int main(){
Char username[10];
printf(“Username: “);
fgets(username,10,stdin);
}

Related

Writing to file and using if statments with loops

I am creating a simple system for people to enter there basic details, have them printed on the screen and once confirmed writen to a text file, is the info is wrong the user enters edit ot be looped back to the beginning of the report and if another input is ented it asks the question again. Im a struggling to get the print to file to work and the two end loops.
#include <stdio.h>
#include <string.h>
int get_line(const char *prompt, char *dest, size_t size) {
printf("%s", prompt);
fflush(stdout);
if (fgets(dest, size, stdin) == NULL) {
dest[0] = '\0';
return 0;
}
dest[strcspn(dest, "\n")] = '\0'; // Lop off potential trailing '\n'
return 1;
}
int main(void)
{
char first_name[20], surname[20], street_no[10], street_name[40], postcode[10], contact_no[20], save_edit_qu[10];
int dd, mm, yy;
get_line(" Enter first name:\n", first_name, sizeof first_name);
get_line(" Enter surname:\n", surname, sizeof surname);
get_line(" Contact Number\n", contact_no, sizeof contact_no);
get_line(" Street Number\n", street_no, sizeof street_no);
get_line(" Street Name\n", street_name, sizeof street_name);
get_line(" Postcode\n", postcode, sizeof postcode);
printf(" First Name : %s\n", first_name);
printf(" Surname : %s\n", surname);
printf(" Contact No.: %s\n", contact_no);
printf(" Street No. : %s\n", street_no);
printf(" Stret Name : %s\n", street_name);
printf(" Postcode : %s\n", postcode);
get_line(" If the informations above is correct please enter SAVE/if you wish to change any informations please enter edit", save_edit_qu, sizeof save_edit_qu);
if (save_edit_qu[0] == 'SAVE' || save_edit_qu[0] == 'save') {
//write info to file
}
if (save_edit_qu[0] == 'EDIT' || save_edit_qu[0] == 'edit') {
//loop back to beginning of report
}
else if ()//loop to beginning of SAVE/EDIT QU
return 0;
}
use strcmp() and use double quotes "" for string !
if (strcmp(save_edit_qu,"SAVE") == 0 || strcmp(save_edit_qu,"save") == 0) {
or test only first character using single quotes like this
if (save_edit_qu[0] == 'S' || save_edit_qu[0] == 's') {
So, there are a couple of things wrong about your program. I'll try to cover them all here before I show you the changes.
Your string comparison is simple nonsensical: save_edit_qu[0] == 'SAVE' simply compares the first character/byte of save_edit_qu to 'SAVE', which itself isn't a proper string literal. You've got to enclose string literals in double quotes in C. And even if you did do that here, it doesn't make sense to compare a character to a string. What you should do is use strcmp from string.h to do the comparison for you. I've placed that inside my fixed version of your program. The format is: strcmp(a,b) == 0 if string a is equal to string b.
You're giving users the ability to edit all their input data. Therefore, you should be placing your data collection in a loop. This allows you to constantly re-collect the data as long as the user isn't done.
do {
// collect data.
} while (!done);
Finally, you're having users perform an action within the data collection loop so that they can choose what they'd like to do with the data. They can either edit, or save. There's also the case they enter neither. In this case, they'll be prompted again. This warrants another control loop inside.
do {
// collect data
do {
// save or edit
} while (!validChoice);
} while (!done);
With this said, here is the working program. I have not implemented the writing-to-file portion for you though. I think you can give that a shot yourself!
#include <stdio.h>
#include <string.h>
int get_line(const char *prompt, char *dest, size_t size) {
printf("%s", prompt);
fflush(stdout);
if (fgets(dest, size, stdin) == NULL) {
dest[0] = '\0';
return 0;
}
dest[strcspn(dest, "\n")] = '\0'; // Lop off potential trailing '\n'
return 1;
}
int main(void)
{
char first_name[20], surname[20], street_no[10], street_name[40], postcode[10], contact_no[20], save_edit_qu[10];
int dd, mm, yy, done = 0;
// Data collection loop: Runs as long as the user opts to edit the data.
do {
// Fetch data.
get_line(" Enter first name:\n", first_name, sizeof first_name);
get_line(" Enter surname:\n", surname, sizeof surname);
get_line(" Contact Number\n", contact_no, sizeof contact_no);
get_line(" Street Number\n", street_no, sizeof street_no);
get_line(" Street Name\n", street_name, sizeof street_name);
get_line(" Postcode\n", postcode, sizeof postcode);
printf(" First Name : %s\n", first_name);
printf(" Surname : %s\n", surname);
printf(" Contact No.: %s\n", contact_no);
printf(" Street No. : %s\n", street_no);
printf(" Stret Name : %s\n", street_name);
printf(" Postcode : %s\n", postcode);
// Action loop: Runs as long as no valid input is given.
do {
get_line(" If the informations above is correct please enter SAVE/if you wish to change any informations please enter edit\n", save_edit_qu, sizeof save_edit_qu);
// Option to quit.
if (strcmp(save_edit_qu, "SAVE") == 0 || strcmp(save_edit_qu, "save") == 0) {
fprintf(stdout, "Writing data to file...\n");
// write data here.
// Set done flag, and exit action loop.
done = 1;
break;
}
// Option to edit.
if (strcmp(save_edit_qu, "EDIT") == 0 || strcmp(save_edit_qu, "edit") == 0 ) {
//loop back to beginning of report
break;
}
// Otherwise ask prompt again ^.
} while (1);
} while (!done);
return 0;
}

fgets - crashes in visual studio, works in gcc

I'm working on something small and I have run into a really small but disturbing problem - the program works in gcc, but crashes in visual studio, when it gets to the fgets command:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void registerUser(char *username);
char path[256] = "C:\\Users\\magshimim\\Desktop\\cproject\\bank\\";
int main() {
int choice = 0;
char username[10];
printf("Welcome to nikitosik's bank program!\n"
"Choose an option :\n"
"0 - Register\n"
"1 - Login to existing account\n");
scanf("%d", &choice);
getchar(); // catch enter
if (!choice) {
registerUser(username);
} else {
//login();
}
}
void registerUser(char *username) { // username is passed, for verification later
FILE *userinfo; // file that contains info of all registered users
FILE *userpathf; // file to open for txt file
char usertxt[256]; // path of data
char userpath[256]; // path of new user data file
char password[15];
strcat(userpath, path);
strcat(usertxt, path);
strcat(usertxt, "users.txt");
userinfo = fopen(usertxt, "a");
printf("Choose a username(max 10 letters): ");
fgets(username, 10, stdin);
username[strcspn(username, "\n")] = 0;
strcat(userpath, username);
strcat(userpath, ".txt");
userpathf = fopen(userpath, "w");
fclose(userpathf);
printf("Choose a password(max 15 letters): ");
fgets(password, 15, stdin);
fprintf(userinfo, "%s\n%s", username, password);
fclose(userinfo);
}
thanks in advance
As above really or initialize the strings first.
memset(userpath, 0, sizeof(userpath));
memset(usertxt, 0, sizeof(usertxt));
Your program has multiple issues:
you concatenate a string into an uninitialized array: this has undefined behavior and may well explain the observed behavior on different systems as undefined behavior may take multiple forms from no consequence at all to a crash or possibly even worse misfortune.
you do not test the return values of scanf, fopen, fgets(). Any invalid or unexpected input may trigger more undefined behavior.
you do not check for potential buffer overflow in strcat(). You should instead use snprintf().
Here is a safer version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int registerUser(char *username, size_t size);
char path[] = "C:\\Users\\magshimim\\Desktop\\cproject\\bank\\";
int main(void) {
int choice = 0;
int c;
char username[10];
printf("Welcome to nikitosik's bank program!\n"
"Choose an option :\n"
"0 - Register\n"
"1 - Login to existing account\n");
if (scanf("%d", &choice) != 1)
return 1;
// consume the rest if the input line
while ((c = getchar()) != EOF && c != '\n')
continue;
if (choice == 0) {
registerUser(username, sizeof(username));
} else {
//login();
}
return 0;
}
int registerUser(char *username, size_t size) { // username is passed, for verification later
char usertxt[256]; // path of data
char userpath[256]; // path of new user data file
char password[17];
FILE *userinfo; // file that contains info of all registered users
FILE *userpathf; // file to open for txt file
printf("Choose a username(max %d letters): ", (int)(size - 2));
if (!fgets(username, size, stdin))
return -1;
username[strcspn(username, "\n")] = 0; // strip newline if any
printf("Choose a password(max 15 letters): ");
if (!fgets(password, sizeof(password), stdin))
return -1;
password[strcspn(password, "\n")] = 0; // strip newline if any
if (snprintf(usertxt, sizeof(usertxt), "%s%s", path, "users.txt") >= (int)sizeof(usertxt))
return -1;
if (snprintf(userpath, sizeof(userpath), "%s%s.txt", path, username) >= (int)sizeof(userpath))
return -1;
userinfo = fopen(usertxt, "a");
if (userinfo == NULL)
return -1;
// create user file
userpathf = fopen(userpath, "w");
if (userpathf != NULL)
fclose(userpathf);
// add user info
fprintf(userinfo, "%s\n%s\n", username, password);
fclose(userinfo);
return 0;
}

How do i remove NULL input in C?

My teacher has asked me to "Fool proof" my code from any sort of misuse, So I have come up with an
program that can remove any empty values (by disallowing them entirely)
Here is the Un-foolproofed code
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
printf("Type something: ");
fgets(text,16, stdin);
printf("You typed: %s",text);
getch();
}
I have made some simple adjustments to ensure there is no error, however, i cannot get the if filter to work properly, as it still allows the NULL input
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
int loop;
do
{
printf("Type something: ");
fgets(text,16, stdin);
if( text[0] == '\0')
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}
}
while(loop > 0);
printf("You typed: %s",text);
getch();
}
I've tried google and i cannot get a solid answer, this probably is some very simple line of code, but sadly i have no idea what it is.
Edit: it's fixed, the if statement should be:
if (text[0] == '\n')
Using the return value from fgets() is the best first step to fool-proofing user I/O.
char text[16];
printf("Type something: ");
if (fgets(text, sizeof text, stdin) == NULL) {
if (feof(stdin)) Handle_stdin_is_closed(); // no more input
if (ferror(stdin) Handle_IOerror(): // very rare event, more common with files
}
// Test is input is is only a '\n'
if (text[0] == '\n')
printf("Try again");
// Look for long line.
size_t len = strlen(text);
if (len + 1 == sizeof text && text[len - 2] != '\n') HandleLongLine();
The next step is to look for scan errors. Let's assume code is to read a long.
errno = 0;
char *endptr;
long = strtol(text, &endptr, 10);
if (errno) Handle_NumericOverflow();
if (text == endptr) Handle_InputIsNotNumeric();
while (isspace((unsigned char) *endptr)) endptr++;
if (*endptr != '\0') Handle_ExtraTextAfterNumber();
Although this is a lot of code, robust handling of hostle user input is best spun off to a helper function where lots of tests can be had.
char * prompt = "Type something: ";
long number;
int stat = GetLong(stdin, prompt, &number); // put all tests in here.
if (stat > 0) Handle_SomeFailure();
if (stat < 0) Handle_EOF();
printf("%ld\n", number);
fgets reads a whole line including the newline into the buffer and 0-terminates it.
If it reads something and then the stream ends, the read line will not have a newline.
If the line does not fit, it won't contain a newline.
If an error occurs before it successfully reads the first character, it returns NULL.
Please read the man-page for fgets: http://man7.org/linux/man-pages/man3/fgets.3.html
According to the fgets() man page
char *fgets(char *s, int size, FILE *stream);
//fgets() returns s on success, and NULL on error or when end of file
//occurs while no characters have been read.
so, you can check the return value of fgets()
n = fgets(text,16, stdin);
if that value is NULL, then nothing have been read.
you can do this by checking the value of n in a for loop,
if( n == NULL)
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}

scanf validation sits and waits for another input. Why?

I was working on this sample exercise, and everything works as I would like it to, but there is one behavior I don't understand.
When providing input: if I make consecutive invalid entries everything seems to work great. But if I enter a number different from 1,2,3 in the case of the first question, or 1,2 in the case of the second question, the program just sits there until a new input is given. If another invalid entry is made, it goes back to the error "invalid entry" message, and if an appropriate number is entered, everything moves along fine.
I do not understand why it stops to wait for a second input...anyone?
Thanks guys.
#include <stdio.h>
static int getInt(const char *prompt)
{
int value;
printf("%s",prompt);
while (scanf("%d", &value) !=1)
{
printf("Your entry is invalid.\nGive it another try: %s", prompt);
getchar();
scanf("%d", &value);
}
return value;
}
int main() {
int wood_type, table_size, table_price;
printf("Please enter " );
wood_type = getInt("1 for Pine, 2 for Oak, and 3 for Mahogany: ");
printf("Please enter ");
table_size = getInt("1 for large, 2 for small: ");
printf("\n");
switch (wood_type) {
case 1:
table_price = (table_size == 1)? 135:100;
printf("The cost of for your new table is: $%i", table_price);
break;
case 2:
table_price = (table_size == 1)? 260:225;
printf("The cost of for your new table is: $%i", table_price);
break;
case 3:
table_price = (table_size == 1)? 345:310;
printf("The cost of for your new table is: $%i", table_price);
break;
default:
table_price = 0;
printf("The cost of for your new table is: $%i", table_price);
break;
}
}
You most likely need to flush your input buffer (especially with multiple scanf calls in a function). After scanf, a newline '\n' remains in the input buffer. fflush does NOT do this, so you need to do it manually. A simple do...while loop works. Give it a try:
edit:
static int getInt(const char *prompt)
{
int value;
int c;
while (printf (prompt) && scanf("%d", &value) != 1)
{
do { c = getchar(); } while ( c != '\n' && c != EOF ); // flush input
printf ("Invalid Entry, Try Again...");
}
return value;
}
The blank line you get if you enter nothing is the normal behavior of scanf. It is waiting for input (some input). If you want your routine to immediately prompt again in the case the [Enter] key is pressed, then you need to use another routine to read stdin like (getline or fgets). getline is preferred as it returns the number of characters read (which you can test). You can then use atoi (in <stdlib.h>) to convert the string value to an integer. This will give you the flexibility you need.
example:
int newgetInt (char *prompt)
{
char *line = NULL; /* pointer to use with getline () */
ssize_t read = 0; /* number of characters read */
size_t n = 0; /* numer of chars to read, 0 no limit */
static int num = 0; /* number result */
while (printf ("\n %s ", prompt) && (read = getline (&line, &n, stdin)) != -1)
{
if ((num = atoi (line)))
break;
else
printf ("Invalid Input, Try Again...\n");
}
return num;
}
If some invalid input is entered, it stays in the input buffer.
The invalid input must be extracted before the scanf function is completed.
A better method is to get the whole line of input then work on that line.
First, put that input line into a temporary array using fgets(),
then use sscanf() (safer than scanf because it guards against overflow).
#include <stdio.h>
int main(int argc, const char * argv[]) {
char tempbuff[50];
int result, d , value;
do
{
printf("Give me a number: ");
fgets( tempbuff, sizeof(tempbuff), stdin ); //gets string, puts it into tempbuff via stdin
result = sscanf(tempbuff, "%d", &value); //result of taking buffer scanning it into value
if (result < 1){ //scanf can return 0, # of matched conversions,
//(1 in this case), or EOF.
printf("You didn't type a number!\n");
}
}while (result < 1);
//some code
return 0;
}
Knowledge from: http://www.giannistsakiris.com/2008/02/07/scanf-and-why-you-should-avoid-using-it/

How to prevent the user from entering more data than the maximum limit?

This code asks the user for data and subsequently a number:
$ cat read.c
#include<stdio.h>
#include<stdlib.h>
#define MAX 10
int main() {
char* c = (char*) malloc(MAX * sizeof(char));
int num;
printf("Enter data (max: %d chars):\n", MAX);
fgets(c, MAX, stdin);
// how do I discard all that is there on STDIN here?
printf("Enter num:\n");
scanf("%d", &num);
printf("data: %s", c);
printf("num: %d\n", num);
}
$
The problem is that apart from the instruction that states the maximum number of chars, there is nothing that stops the user from entering more, which is subsequently read into num as junk:
$ ./read
Enter data (max 10 chars):
lazer
Enter num:
5
data: lazer
num: 5
$ ./read
Enter data (max 10 chars):
lazerprofile
Enter num:
data: lazerprofnum: 134514043
$
Is there a way to discard all that is there on STDIN after the fgets call?
The scanf() function is terrible for user input, and it's not that great for file input unless you somehow know your input data is correct (don't be that trusting!) Plus, you should always check the return value for fgets() since NULL indicates EOF or some other exception. Keep in mind that you get the user's newline character at the end of your fgets() data unless the maximum is reached first. I might do it this way as a first pass:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10
void eat_extra(void) {
int ch;
// Eat characters until we get the newline
while ((ch = getchar()) != '\n') {
if (ch < 0)
exit(EXIT_FAILURE); // EOF!
}
}
int main() {
char c[MAX+1]; // The +1 is for the null terminator
char n[16]; // Arbitrary maximum number length is 15 plus null terminator
int num;
printf("Enter data (max: %d chars):\n", MAX);
if (fgets(c, MAX, stdin)) { // Only proceed if we actually got input
// Did we get the newline?
if (NULL == strchr(c, '\n'))
eat_extra(); // You could just exit with "Too much data!" here too
printf("Enter num:\n");
if (fgets(n, sizeof(n) - 1, stdin)) {
num = atoi(n); // You could also use sscanf() here
printf("data: %s", c);
printf("num: %d\n", num);
}
}
return 0;
}
To my knowledge, the only portable solution is to exhaust the buffer yourself:
while (getchar() != EOF);
Note that fflush(stdin); is not the answer.
EDIT: If you only want to discard characters until the next newline, you can do:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
What "can happen" to fgets?
it returns NULL when there is an error in input
it returns NULL when it finds an EOF before any "real" characters
it returns the pointer to the buffer
the buffer wasn't completely filled
the buffer was completely filled but there is no more data in input
the buffer was completely filled and there is more data in input
How can you distinguish between 1 and 2?
with feof
How can you distinguish between 3.1., 3.2. and 3.3.
By determining where the terminating null byte and line break were written:
If the output buffer has a '\n' then there is no more data (the buffer may have been completely filled)
If there is no '\n' AND the '\0' is at the last position of the buffer, then you know there is more data waiting; if the '\0' is before the last position of the buffer, you've hit EOF in a stream that doesn't end with a line break.
like this
/* fgets fun */
/*
char buf[SOMEVALUE_LARGERTHAN_1];
size_t buflen;
*/
if (fgets(buf, sizeof buf, stdin)) {
buflen = strlen(buf);
if (buflen) {
if (buf[buflen - 1] == '\n') {
puts("no more data (3.1. or 3.2.)"); /* normal situation */
} else {
if (buflen + 1 == sizeof buf) {
puts("more data waiting (3.3.)"); /* long input line */
} else {
puts("EOF reached before line break (3.1.)"); /* shouldn't happen */
}
}
} else {
puts("EOF reached before line break (3.1.)"); /* shouldn't happen */
}
} else {
if (feof(stdin)) {
puts("EOF reached (2.)"); /* normal situation */
} else {
puts("error in input (1.)");
}
}
The usual, incomplete tests, are buf[buflen - 1] == '\n' and checking fgets return value ...
while (fgets(buf, sizeof buf, stdin)) {
if (buf[strlen(buf) - 1] != '\n') /* deal with extra input */;
}
I would read the data and then check it for user error:
bool var = true;
while var {
printf("Enter data (max: %d chars):\n", MAX);
fgets(c, MAX, stdin);
// how do I discard all that is there on STDIN here?
if(strlen(c) <= 10)
var = false;
else
printf("Too long, try again! ");
}
On the other hand, if you don't want to do this, just read num twice and discard the first one.

Resources