simple c scanf is not reading and parsing my input - c

I have created Date struct to store date format as date, month, year which is inputed by the user as a single line string seperated by space.
I want to split the input and store it accordingly. I have used simple C sscanf() to split and store my input in struct Date. But when I try to print my data it's showing some garbage value, I don't know what is missing.
Help me to clear this issue.
My code:
Input: 24 Jan 1980
output: 24 ? -978635323
here is my C code.
struct Date
{
int date;
char* month;
int year;
};
int main()
{
struct Date date[1];
char* string;
scanf("%s",string);
sscanf(string,"%d %s %d",&date[0].date,date[0].month,&date[0].year);
printf("%d %s %d",date[0].date,date[0].month,date[0].year);
return 0;
}
Thanks in advance.

it works for me. You can check it.
struct Date
{
int dat;
char month[20];
int year;
};
int main()
{
struct Date date[1];
char str[20];
scanf("%[^\n]%*c", str);
sscanf(str,"%d %s %d",&date[0].dat,&date[0].month,&date[0].year);
printf("%d %s %d",date[0].dat,date[0].month,date[0].year);
return 0;
}

EXPLANATION
In your code, you have declared two char * pointers char *month and char *string, and trying to store string values in them. You have to understand that these two are mere pointers. All they can store are memory addresses to char arrays. It is true that an array variable is interchangeable with a pointer in C. But an array declaration also involves a size attribute.
When you declare a character array as:
char str[10];
It actually reserves a block of size 10 in memory, implicitly creates char *str, and stores the base address of the newly created block in str. But when you just declare char *str, all it does is create a pointer. This doesn't have any associated memory block for the array.
That's why you have to declare a character array of some size before storing strings in it with scanf(). Or you have to dynamically allocate memory with calloc or malloc after declaring the char * pointer. Only then can you store a string input in it.
I have modified your code to work properly. It produces the desired output now. Hope this helps.
WORKING CODE
#include <stdio.h>
#include <stdlib.h>
struct Date
{
int date;
char month[10];
int year;
};
int main()
{
struct Date date[1];
char string[20];
scanf("%[^\n]s",string);
sscanf(string,"%d %s %d",&date[0].date,date[0].month,&date[0].year);
printf("%d %s %d",date[0].date,date[0].month,date[0].year);
return 0;
}
EDIT
They themselves are integers actually (as are all pointers).
As mentioned by anastaciu, pointers are not equivalent to integers per se. You can follow the links given in his comments for more knowledge. I had mentioned that statement to assert the difference between pointers and array declarations.

char* string is an uninitialized pointer, it cannot hold a string, you need to allocate memory, initialize it as an array of chars or point it to a variable with memory already allocated or to an existing array of chars.
Your structure member month suffers from the same problem.
A -Wall flag in your compiler should give you a warning:
'string is used uninitialized in this function [-Wuninitialized]'
Another problem is that %s only gets a string, when it finds a blank space, it stops reading, so it can only read 24 in your case.
Though "%[^\n]s" can work, a better solution would be to use fgets, it's a safer function since you can limit the size of the input to the size of receiving container, unlike scanf.
#include <stdio.h>
#define SIZE 100
struct Date
{
int date;
char month[SIZE];
int year;
};
int main()
{
struct Date date[1];
char string[SIZE];
fgets(string, sizeof(string), stdin);
sscanf(string,"%d %s %d",&date[0].date, date[0].month, &date[0].year);
}

Related

Is this a misunderstanding of the functionality of strcpy()?

#include <stdio.h>
#include <string.h>
int main(void) {
int number_of_members;
char family[number_of_members][20][number_of_members][20];
char member_name[20];
char birth_state[20];
char family_last_name[20];
printf("What is the last name of the family?\n");
scanf("%s", &family_last_name);
printf("How many members do you want to create?\n");
scanf("%d", &number_of_members);
int const FAMILY_SIZE = number_of_members;
number_of_members = number_of_members -1;
printf("Enter the family member name: \n");
for(number_of_members;number_of_members>-1;number_of_members--)
{
scanf("%s", &member_name);
strcpy(family[number_of_members], member_name);
printf(" %d %s %s\n",number_of_members, member_name, family_last_name);
}
printf("%s, %s ", family[0], family[1]);
return 0;
}
Here is the output:(from Ideone.com)
Ideone.com with code
The input to this code is: Layne , 2 , tim , jim.
When run, it shows the correct index with the name in the array however, once out it will show the last entered name, jim, as family1 and family[0]. Am I not understanding how strcpy() works? or is it a logic error?Some assistance soon would be appreciated!
This is very very wrong
int number_of_members;
char family[number_of_members][20][number_of_members][20];
Because you haven't initialized number_of_members.
Because it doesn't make sense whatsoever, it's not possible that you really need this kind of array.
And yes, if you enable compiler warnings it will hit you in your nose with a stick, because
strcpy(family[number_of_members], member_name);
shouldn't even compile and is undefined behavior since the type of family[number_of_members], is an array of arrays of arrays of char.
strcpy can take an array of char's because it will be automatically converted to a char poitner, and provided that the contents of the array comply with what a c string is, then strcpy() will work correctly, in your case the behavior is undefined because almost surely the '\0' will never be found in the destination pointer.
instead of
int num_of_members;
char family[number_of_members][20][number_of_members][20];
which is not C code, do this
#define MAX_MEMBERS 20
char family[MAX_MEMBERS][20];
which creates a rectangular array of arrays each of 20 bytes long

Breaking down a pointer str to smaller pointers str

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINES 25
int get_lines(char *studentinfo[]);
int main()
{
int onswitch=0;
char *studentinfo[100];
char *fname[100];
char *lname[100];
char *score[100];
int counter;
int x,y;
char temp,temp2,temp3;
counter=get_lines(studentinfo);
for (y=0; y<counter; y++)
{
temp=strtok(studentinfo, " ");
fname[y]=malloc(strlen(temp));
strcpy(fname[y],temp);
temp2=strtok(NULL, " ");
lname[y]=malloc(strlen(temp2));
strcpy(lname[y],temp2);
temp3=strtok(NULL," ");
score[y]=malloc(strlen(temp3));
strcpy(score[y],temp3);
int get_lines(char *studentinfo[])
{
int n=0;
char buffer[80];
puts("Enter one line at a time; enter a blank when done.");
while ((n<MAXLINES) && (gets(buffer) !=0) && (buffer[0] != '\0'))
{
if ((studentinfo[n]=(char*)malloc(strlen(buffer)+1))==NULL)
return -1;
strcpy(studentinfo[n++],buffer);
}
return n;
}
Alright guys I am trying to make program that takes in student information for sorting later. I have taking the input down with the function on the bottom. I am trying to break down to the student information into three different pointers for sorting. The problem I am having is trying to allocate enough memory to store then information. Then actually storing the memory in that pointer location.
A simple input is
John Smith 80
^fname ^lname ^score
I thought the for loop I had would work in theory but it didnt (error: Unhandled exception at 0x0F3CFA50 (msvcr110d.dll) in ConsoleApplication3.exe: 0xC0000005: Access violation reading location 0xFFFFFF8) can anybody point me in the right direction (not just give me a loop that works) ?
With your implementation, you get an access violation. You are trying to touch a dirty region of memory. Here is the solution with an explanation below
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINES 25
int get_lines(char *studentinfo[]);
int main()
{
int onswitch=0;
char *studentinfo[100];
char *fname[100];
char *lname[100];
char *score[100];
int counter;
int x,y;
char *temp,*temp2,*temp3;
counter=get_lines(studentinfo);
for (y=0; y<counter; y++)
{
temp=strtok(studentinfo[y], " ");
fname[y]=malloc(strlen(temp));
strcpy(fname[y],temp);
temp2=strtok(NULL, " ");
lname[y]=malloc(strlen(temp2));
strcpy(lname[y],temp2);
temp3=strtok(NULL," ");
score[y]=malloc(strlen(temp3));
strcpy(score[y],temp3);
printf("%s %s %s", fname[y], lname[y], score[y]);
}
}
int get_lines(char *studentinfo[])
{
int n=0;
char buffer[80];
puts("Enter one line at a time; enter a blank when done.");
while ((n<MAXLINES) && (gets(buffer) !=0) && (buffer[0] != '\0'))
{
if ((studentinfo[n]=(char*)malloc(strlen(buffer)+1))==NULL)
return -1;
strcpy(studentinfo[n++],buffer);
}
return n;
}
First off, you are missing an ending bracket } for your for loop as well as your main function. So add those.
Your getlines function is all good.
Your for loop is screwed up. In particular, you confused the data types you are passing. Remember, you have declared an array of POINTERS.
temp=strtok(studentinfo, " ");
This is saying, hey, let's tokenize my array pointer. You don't want this. You want to tokenize the yth element in that array! So element 0 in your array is a pointer to the string "JOHN SMITH 80". This is what we want to tokenize. Otherwise what you had was trying to tokenize somthing along the lines of 0xabcdabcd or whatever the memory address of the allocated array was.
temp=strtok(studentinfo[y], " ");
This is the correct way. It says tokenize the first element, which is a pointer to our string.
Your next problem is your temp variables. You are calling strlen(temp). strlen expects a pointer to a string. You are passing the data of the char itself. Actually, you are passing the return pointer (likely null) of the strtok function that was stored in your char byte.
char temp,temp2,temp3;
You declared three bytes for the type char. What you wanted was three char * to hold pointers to your string tokens.
char *temp,*temp2,*temp3;
With this, strlen takes in these pointers, mallocs some space for your fname elements, and then you proceed to copy into this element using strcpy.
Note: strcpy also takes two pointers, one for destination, one for source, so again your temp variables needed to be pointers to your strings.
Hope this helps let me know if you are confused with my explanation at all.
strcpy takes characters until it reaches a \0 character. You want to check out the strncpy or memcpy functions, and then manually add the null terminator.

Structures in C - not printing the whole string

Working on some self study in understanding structures in C.
I've made a small program that gets info from the user and then prints it back via functions.
I used two different methods of handing off the data using a couple examples in the C Primer Plus book.
What happens is that I can input the data but when it prints it back out the numeric data is ok but only the first character in each string is printed with garbage after it.
My code is below for review. I can't figure out what the issue is.
Any help would be great. Thanks!
#include <stdio.h>
#include <stdlib.h>
struct stats {
char name;
char city;
int wins;
int losses;
int draws;
};
void screen_print(char name,char city,int wins,int losses,int draws);
void team_input (struct stats * ptr);
int main()
{
struct stats team;
team_input(&team);
screen_print(team.name,team.city,team.wins,team.losses,team.draws);
return 0;
}
void screen_print(char name,char city,int wins,int losses,int draws)
{
// system("cls");
printf("==================================================\n");
printf("Name:\t\t\t%s\n",&name);
printf("City:\t\t\t%s\n",&city);
printf("Number of Wins:\t\t%d\n",wins);
printf("Number of Losses:\t%d\n",losses);
printf("Number of Draws:\t%d\n",draws);
printf("==================================================");
}
void team_input (struct stats * ptr)
{
system("cls");
printf("Enter Team name: ");
scanf("%s",&(ptr->name));
printf("\nEnter City:");
scanf("%s",&(ptr->city));
printf("\nEnter Wins:");
scanf("%d",&(ptr->wins));
printf("\nEnter Losses:");
scanf("%d",&(ptr->losses));
printf("\nEnter Draws:");
scanf("%d",&(ptr->draws));
}
name and city are single characters only: they are not strings.
scanf("%s",&(ptr->name)); is invalid and will be overwriting memory as an attempt is being made to read a string into a single char.
printf("%s", &name); expects name to be a null terminated string, so it will print the name char then random characters until a null is found somewhere in memory.
Change to:
struct stats {
char name[20]; /* Or greater than 20 if required */
char city[20];
int wins;
int losses;
int draws;
};
or dynamically allocate memory before populating if maximum possible length of name and city are unknown beforehand.
Change the printf() statements to:
printf("Name:\t\t\t%s\n", name);
printf("City:\t\t\t%s\n", city);
and scanf() statements to:
scanf("%s",ptr->name);
scanf("%s",ptr->city);
and screen_print() signature to:
void screen_print(char* name,char* city,int wins,int losses,int draws)
You're using single chars instead of arrays of chars. Both when inputting and outputting, the system is getting the memory address of a char, thinking that it's a string, and writing to/reading from it without any bounds check. So the adjacent memory is accessed as well, even though you didn't intend to.
You're lucky that your numeric data is input after the textual ones, or else even those would be wrong. Since a struct will usually occupy contiguous positions in memory, it's likely that they are being overwritten when you input your strings. That "garbage" you're seeing is in fact the data in the rest of your struct, plus anything that's "close" to it in memory, until an empty value is found (\0, interpreted as the null char).
In your struct, only one char is allocated for name and city. To hold a string, you need to specify the length at declaration.
struct stat {
char city[20];
char name[20];
...
}
String in C is quite tricky. It is an array of characters using an invisible '\0' for the ending. A string "hello" is actually 'h', 'e', 'l', 'l', 'o', '\0' in the memory.

strncmp/strcpy corrupting source

today i was trying to get friendly with char * string... but it seems im failing :)
Every time i call strcmp/strncmp/strcpy function my source gets corrupted...
here is the snippet
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
int UID;
char name[20];
char surname[20];
};
char * getString(int minChars, int maxChars);
struct student * myStud;
int main(int argc, char** argv) {
myStud = (struct student*)malloc(sizeof(struct student));
while(1)
{
printf("\nEnter new name: ");
strcpy(myStud->name,getString(1,19));
printf("\n The values is now %s",myStud->name);
}
return (EXIT_SUCCESS);
}
char * getString(int minChars, int maxChars)
{
char string[maxChars+1];
scanAgain:
scanf("%s",&string);
if(strlen(string)<minChars)
{
printf("\nToo few symbols, try again: ");
goto scanAgain;
}
if(strlen(string)>maxChars)
{
printf("\nToo many symbols, try again: ");
goto scanAgain;
}
string[maxChars]='\0';
return(string);
}
Output:
Enter new name: Alekasdasd
The values is now Alekasda�#
Enter new name:
im just a beginner so it might be something very simple... might be not.
oh and by the way, using linux and netbeans as SDK, gcc as compiler.
You're returning a pointer to a stack variable.
char * getString(int minChars, int maxChars)
{
char string[maxChars+1];
When getString returns, string is invalid. Your return value points to this invalid string.
Use:
char * getString(int minChars, int maxChars, char * string) {
return string;
}
...
char string[100];
getString(1, 2, string);
Also, goto? Stop that please - use for, while do, do while but not goto
char * getString(int minChars, int maxChars)
{
char string[maxChars+1];
...
return(string);
}
The "string" array here is only allocated for the scope of the getString() function. Once it returns (goes out of scope), it ceases to exist and will be overwritten by the rest of your program. The "return(string)" statement returns the pointer of this data that's not allocated anymore -- not the data itself. This happens due to the implicit array-to-pointer conversion in C.
Instead of doing this, your getString() function should take a char* as an argument, which is allocated in the calling function.
I see two problems with your getString() function:
The string variable must be declared static so that the memory used for it is not released (stack, popped) when the function returns.
The parameter to scanf() you do not want the & token, but simply the pointer to the buffer, string.
That is, change the lines:
char string[maxChars+1];
scanf("%s",&string);
to read
static char string[maxChars+1];
scanf("%s",string);
The reason you do not want the ampersand in the scanf() call is the following from the man page, man 3 scanf:
s Matches a sequence of non-white-space characters; the next
pointer must be a **pointer to character array** that is long enough
to hold the input sequence and the terminating null character
('\0'), which is added automatically. The input string stops at
white space or at the maximum field width, whichever occurs
first.
240 lines is not a "snippet".
As James suggested in his comment, reduce the code to the minimum number of lines needed to reproduce the problem. At that stage the cause of the problem should become obvious to you -- if not try posting again.

Copy a string into a char array

Hello i want to copy the input of a user into an array of char which is defined in a struct. Sincerly i have no idea how to do this.
#include <stdio.h>
#include <stdlib.h>
int main ()
{
struct employee
{
char firstname[11];
char lastname[11];
char number[11];
int salary;
}
int i;
int nemps;
const int maxemps = 5;
struct employee* emps[maxemps];
printf("How many employees do you want to store?(max:5): ");
scanf("%d", nemps);
for (i = 0; i < nemps; i++)
{
printf("Employee 1./nLast name:");
scanf("....")// Read the string and copy it into char lastname[]
}
}
First off struct employee* emps[maxemps]; creates an array of pointers to struct employee with array size maxemps. You haven't actually set aside any space in memory for the actual structs, just the pointers that will point to them. To dynamically allocate space on the heap for your structs so you can use them in a meaningful way, you'll need to loop over a call to malloc() like so:
for (i = 0; i < maxemps; i++) {
emps[i] = malloc(sizeof(struct employee));
}
You'll also want a similar loop at the end of your program which will free() each pointer.
Next, when you are getting input from a user you really want to be using fgets() over scanf() because fgets() allows you to specify the number of characters to read in so you can prevent overflows on your destination buffer.
Update
If you want to work with a single struct employee without the use of pointers this is accomplished by declaring one or more struct employee on the stack and then using the . member access operator as follows:
struct employee emp;
fgets(emp.lastname, sizeof(emp.lastname), stdin);
Update2
I found a number of errors in your code. Please see this link for a working sample with comments.
You only need:
scanf("%10s", (emps[i])->last_name);
Here "%10s" denotes a string with a maximum length of 10, and it will load the string to last_name.
In C the string is represented as a char array, with '\0' as the end.
Using scanf here is vulnerable to buffer attacks if the user-input is longer than 10: http://en.wikipedia.org/wiki/Scanf#Security, so you need to assign a maximum length to the format.

Resources