condition check on scanf ()or get on input - c

I have to print first, middle and last name in abbreviation from a full-name input from from user,e.g ram kumar shahu as r.k. shahu.Problem is that if I get only first name and last name then I should print like r. shahu.
Below is my code so far.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char fname[10],mname[10],lname[10];
printf("Enter the name:\n");
if(lname==NULL)
{
scanf("%s %s ",fname,mname);
}
else
scanf("%s %s %s",fname,mname,lname);
if(lname==NULL)
{
printf("%c.%s",fname[0],mname);
}
else
printf("%c.%c.%s",fname[0],mname[0],lname);
return 0;
}

char fname[10],mname[10],lname[10];
char line[30];
int state;
printf("Enter the name:\n");
fgets(line, sizeof line, stdin);
state = sscanf(line, "%9s %9s %9s", fname, mname, lname);
if(state == 2){
printf("%c.%s\n",fname[0], mname);
} else if(state == 3){
printf("%c.%c.%s\n",fname[0], mname[0], lname);
}

To start with, you are dealing with a case where you don't know the length of the input. I would suggest you to take the following approach.
Read the whole input from user using fgets()
Start tokenizing based on fixed delimiter , maybe a space. You can use strtok()
If token count is 2, the tokens are considered as first and last name
If token cout is 3, they are first, middle and last names.
Then, you can print out the first element from all the tokens required (1 or 2). That is, in case 3, you print the first element of the first token and the complete second token, in case of 4, you print the first elements from first and second token and the third in full.

Related

is it possible to use fgets to store the userinput from a single line into 2 arrays?

I'm trying to store the user input name into the structure. I am using fgets instead of scanf because I want to control the length of the user input. Is it possible to use fgets to store the user input from a single line separated by white space into 2 arrays (for my case it's the lastName[10] and firstName[10])?
Is the only way to use printf function in order to print 2 strings that are taken from the user by firstName and lastName individually?
#include <stdio.h>
#include <string.h>
struct names {
char lastName[10];
char firstName[10];
} names;
int main() {
printf("Enter names (firstName lastName): \n");
fgets(names.firstName, 10, stdin);
fgets(names.lastName, 10, stdin);
printf("first Name: %s last Name: %s \n", names.firstName, names.lastName);
return 0;
}
The problem with the standard C functions in stdio.h is that they are easy to get wrong which may lead to buffer overflow. Here is a safe way to read the names using a custom function:
#include <ctype.h>
#include <stdio.h>
#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])
struct names {
char lastName[10];
char firstName[10];
} names;
void ReadName(char name[], int nameLen)
{
int ch, i;
/*skip whitespace*/
do {
ch = getchar();
} while (isspace(ch));
i = 0;
while ((isgraph(ch) || ((unsigned char) ch >= 128)) && (i < nameLen - 1)) { /*accept any UTF-8 byte*/
name[i] = ch;
i++;
ch = getchar();
}
name[i] = '\0';
}
int main(void)
{
printf("Enter names (first name last name): \n");
ReadName(names.firstName, LEN(names.firstName));
ReadName(names.lastName, LEN(names.lastName));
printf("First name: %s\nLast name: %s\n", names.firstName, names.lastName);
return 0;
}
Edit: Made ReadName accept UTF-8 characters.
You can declare a character array as for example
char line[20];
(the size of the array can be greater than 20) and read data in this character array
fgets( line, sizeof( line ), stdin );
when you can use the function sscanf to read lastName and firstName like
sscanf( line, "%s %s", names.firstName, names.lastName );
Also by determining the position of a blank in line you can determine that each substring is not greater than 9 characters.
Actually, what you are trying to do (including controlling the length of the user input) is better accomplished using scanf:
scanf("%9s %9s",names.firstName,names.lastName);
The "%9s" limits each string to 9 characters (to avoid overflowing your strings), and the space in the format string scans for whitespace, so you can enter first and last names on a single input line.

How to take the first and last name as one and print in file?

In this code, I am facing a problem that is whenever I try to enter the first and last name, it only prints the first name in the file. But I want to print the last name also. The space between the two words should not be removed. Instead first and last should be considered as one.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *fp = fopen("new.csv", "w");
char name[50];
printf("Enter your name: ");
scanf("%s", name);
fprintf(fp, "%s", name);
fclose(fp);
return 0;
}
If you use %s, fscanf read until a whitespace character appear, stopping after the first name.
If there's nothing else at the line e.g. before the user presses Enter, you could use fgets to read in the whole line. The parameters there are the file stream, a pointer to the character array and it's size:
char name[50];
fgets(stdin, name, sizeof(name));
If you still want to use scanf, you could also use %[^\n] instead of %s as mentioned here:
char name[50];
scanf("%49[^\n]", name);
To prevent buffer overflow, you should use scanf only with the buffers size minus one written directly after % (defining maximum field width).
If there's other data in the line after first and last name, you could read them in separately and put them together afterwards:
#include <stdio.h>
int main() {
char firstName[50];
char lastName[50];
scanf("%49s %49s", firstName, lastName);
char name[50];
snprintf(name, sizeof(name), "%s %s", firstName, lastName);
printf("%s\n", name);
}

s expects argument of type char c but argument 2 has type 'int' warning and bad return

Yes ,I know that this question was already asked for many times ,but none of these helped me to discover the problem (duplicate...yeah). I want to read from input a series of strings into an array and then search from 'First Name'. If the name exist ,I want to display all the data stored in that element of array (I attached the code to undestand easily). When I run it ,I read from keyboard all the data ,but it returns me absolutely nothing.
#include<stdio.h>
typedef struct record {
char name[10],lname[10],phone[10],bday[10];
};
void main() {
struct record rec;
char search;
int i,nr;
printf("\nInput number of records: ");
scanf("%d",&nr);
for (i=0 ; i<nr ;i++) {
printf("First name: ");
scanf("%s",&rec.name[i]);
printf("Last name: ");
scanf("%s",&rec.lname[i]);
printf("Phone: ");
scanf("%s",&rec.phone[i]);
printf("Bday: ");
scanf("%s",&rec.bday[i]);
}
printf("Input the first name for searching: ");
scanf("%s",&search);
for (i=0 ;i<nr;i++) {
if (search == rec.name[i]) {
printf("First name: %s\nLast name: %s\nPhone: %s\nB-day: %s",rec.name[i],rec.lname[i],rec.phone[i],rec.bday[i]);
}
}
}
NOTE: I already replaced
scanf("%s",&rec.name[i]);
with
scanf("%s",rec.name[i]);
but no effect.
I believe there are a lot of problems with your code.
Firstly in this line:
scanf("%s",&search);
You have declared search as only a char, when really you want an array of chars. You also don't need & with search, as an array decays to a pointer to the first element.
It instead should be like this:
char search[10];
scanf("%9s", search); /* %9s to avoid buffer overflow */
You need to make this change to all your other scanf() calls, as this seems to be everywhere in this code.
It also seems that you want to create an array of records(structures), So you might need to make this after getting the value of nr. You can create it like this:
struct record rec[nr]; /* array of nr structures */
This also means calls like this:
rec.name[i]
Don't make sense, as you are iterating over the characters within a name, not over all the records in struct records.
This needs to be instead:
rec[i].name
Secondly, Your using == to compare strings, when you should be using strcmp instead. Using == will only compare the base address of the strings, not the actual contents of strings.
Your line should be this instead:
if (strcmp(search, rec[i].name) == 0) {
If you read the manual page for strcmp(), checking for a return value of 0 means that both strings are equal in comparison.
Lastly, in your first scanf() call:
scanf("%d",&nr);
You should really check the return value of this:
if (scanf("%d", &nr) != 1) {
/* exit program */
}
Note: For reading strings, you should really be using fgets instead. You can try upgrading to this later, but I think it is better to understand these basics first.
Here is working example of what your program should do:
#include <stdio.h>
#include <string.h>
#define STRSIZE 10
typedef struct {
char name[STRSIZE+1]; /* +1 to account for null-btye at the end */
char lname[STRSIZE+1];
char phone[STRSIZE+1];
char bday[STRSIZE+1];
} record;
int main() {
char search[STRSIZE+1];
int i,nr;
printf("\nInput number of records: ");
if (scanf("%d", &nr) != 1) {
printf("Invalid input.\n");
return 1;
}
record rec[nr]; /* array of records */
for (i = 0; i < nr ; i++) {
printf("First name: ");
scanf("%10s", rec[i].name);
printf("Last name: ");
scanf("%10s", rec[i].lname);
printf("Phone: ");
scanf("%10s", rec[i].phone);
printf("Bday: ");
scanf("%10s", rec[i].bday);
}
printf("Input the first name for searching: ");
scanf("%10s", search);
for (i = 0; i < nr; i++) {
if (strcmp(search, rec[i].name) == 0) {
printf("First name: %s\nLast name: %s\nPhone: %s\nB-day: %s\n",rec[i].name,rec[i].lname,rec[i].phone,rec[i].bday);
} else {
printf("Record not found.\n");
}
}
return 0;
}
The numeric input leaves a new line character in the input buffer, which is then picked up by the character input. when numeric input with scanf() skips leading white space, character input does not skip this leading white space.
Use a space before %c and it will help you cause if space is not used then a buffer added with value .so that use space before %c
scanf(" %c",&rec.name[i]);

Comparing strings in C using strcmp

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.

Verifying Input in C

I'm trying to write a simple binary calculator to get reaquainted with C. for some reason the first input verification works fine, and even though the second verification for the numbers is written in almost the same way, if the user enters faulty input, the while loop just loops infinitely without ever waiting for new user input. Here is the code, and thanks for the help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char operator[20];
char valid_operator[4] = "+-*/";
printf("Enter operator: ");
scanf("%s", operator);
printf("You entered: %s\n", operator);
while(strchr(valid_operator, (int)operator[0]) == NULL) {
printf("%s is not a valid operator. Enter +, -, /, or *: ", operator);
scanf("%s", operator);
}
The code works up until here. This next part is thrown into an infinite loop if the user enters faulty input the first time. The re-prompting never happens.
int input1;
int input2;
printf("Enter the two inputs (separated by whitespace): ");
int num_ints = 1;
num_ints = scanf("%d %d", &input1, &input2);
printf("Input 1: %d. Input 2: %d.\n", input1, input2);
while(num_ints < 2){
printf("Invalid input. Enter two integers separated by whitespace: ");
num_ints = 0;
num_ints = scanf("%d %d", &input1, &input2);
printf("Input 1: %d. Input 2: %d.\n", input1, input2);
}
return 0;
The reason it loops infinitely without ever waiting for new user input is that when scanf fails to read a char in the requested format (%d in your case) it won't advance the file pointer and at the next iteration of the loop it will try to read the same incorrect char again.
This is consistent with POSIX: http://pubs.opengroup.org/onlinepubs/009695399/functions/fscanf.html
if the comparison shows that they are not equivalent, the directive shall fail, and the differing and subsequent bytes shall remain unread.
Also, return value from the man scanf:
...return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
So, you better combine fgets and sscanf.
do {
char buf[BUFSZ];
printf("Enter the two inputs (separated by whitespace): ");
if(fgets(buf, BUFSZ, stdin) == NULL)
{
/* Error exit. */
break;
}
num_ints = sscanf(buf, "%d %d", &input1, &input2);
} while(num_ints != 2);
You need to clear stdin. If you input a non-integer in your example "1 t", "t" is not consumed (left in the stream). Add this to your loop:
while(num_ints < 2){
while (fgetc(stdin) != '\n'); // clear input
. . .
See C program loops infinitely after scanf gets unexpected data for a good description of the issue.

Resources