c reading string input error - c

struct employee {
int employeeId;
double payrate;
char *inputname;
};
int main (void){
//remember the struct before employee
struct employee davidB;
fgets(davidB.inputname, 20, stdin);
davidB.employeeId = 1;
davidB.payrate = 45020.50;
printf("The employees name is %s\n The employees id num is %d\n The employees payrate is %f\n", davidB.inputname, davidB.employeeId, davidB.payrate);
struct employee ericG;
printf("Please enter employee name, id number, and payrate\n");
scanf("%s", ericG.inputname);
scanf("%d", &ericG.employeeId);
scanf("%lf", &ericG.payrate);
printf("The employees name is %s\n The employees id num is %d\n The employees payrate is %f\n", ericG.inputname, ericG.employeeId, ericG.payrate);
return 0;
}
My questions involve:
fgets(davidB.inputname, 20, stdin);
scanf("%s", ericG.inputname);
Why does the first one work and why does the second one cause stack overflow? Furthermore, when can I directly assign a "string" to a pointer, and when does it need to be a pre-defined char array?
for example:
const char *string = "Hey"; //works? so can't I do the same with the scanf above?

You need to allocate memory in order to use those functions, otherwise you get stack overflow since this pointer (davidB.inputname) is pointing to garbage.
One option would be to define it like char inputname[21]; but this will only work for the fgets function since you can limit the number of chars your read.
But with scanf there is nothing you can do unless you can be 100% on the size of the string you're about to read so it's better avoid it otherwise.

It is just random luck that one way works, but the other does not. Both methods are incorrect, as you are not allocating any memory for inputname to point to. So, the functions are just inputting data to some random memory location.
The const char *string = "Hey" works because this is static data, and the compiler is allocating space for it somewhere.

You haven't allocated memory for `inputname. So both invoke undefined behaviour. So both don't work, not in legal C anyway.
But when you directly assign like this:
const char *string = "Hey";
string merely points to a string literal. So there's no need for memory allocation there.
So in this way, you can directly assign to the struct member:
struct employee davidB;
davidB.inputname = "Eric"; // Thiis is valid.
davidB.employeeId = 1;
davidB.payrate = 45020.50;
Otherwise, you have to dynamically allocate memory for inputname:
struct employee davidB;
davidB.inputname = malloc(256);
fgets(davidB.inputname, 256, stdin);
davidB.employeeId = 1;
davidB.payrate = 45020.50;

Related

format '%s' expects argument of type '*char' but argument 2 has type 'int'

When I try to compile my program I get the warning message in the title and when I run it after scanning the names and scores it just stops. I encountered this problem a lot of times while practicing working with strings, but I haven't been able to find a solution.
#include <stdio.h>
struct students {
char name[20];
int score[20];
} student;
int main() {
int i, n;
printf("Number of students:\n");
scanf("%d", &n);
for(i=0; i<n; i++) {
printf("Name of the student:\n");
scanf("%s", &student.name[i]);
printf("Score of the student:\n");
scanf("%d", &student.score[i]);
}
for(i=0;i<n;i++) {
if(student.score[i] >= 15) {
printf("%s passed the exam\n", student.name[i]); }
else {
printf("%s failed the exam\n", student.name[i]);
}
}
return 0;
}
There are several issues:
printf("%s passed the exam\n", student.name[i]);
student.name[i] is a char but the %s format specifier wants a pointer to char.
But the actual problem is that your declaration of students is not what you need. Following structure declares one student whose name can be up to 19 characters long and having 20 scores.
struct students {
char name[20];
int score[20];
} student;
But you need 20 (or more?) students each of them having one score:
struct student {
char name[50]; // name up to 49 characters
int score; // score
} student;
struct student students[20]; // array of 20 students
Il leave the implementation of the code to the reader as an exercise.
You need to get familiar with following concepts:
arrays
structs
strings
basics of scanf and printf
All these topics are covered in your C text book.
Your code have quite a few issue.
1) student should be array ( or dynamically memory allocated).
2) scanf of string needs to be done as
scanf("%s", student[i].name)
Or
scanf("%s", &student[i].name[0])
3) Still you would have issue if string length crosses 20 byte (include nul character).
char name[20];
sets aside space for a single 20-character string, so students.name[i] refers to a single character (which gets promoted to type int in the scanf call).
To define an array of strings, you need a 2D array of char, like
char name[NUMBER_OF_STRINGS][MAX_STRING_LENGTH+1];
and you read it as
scanf( “%s”, student.name[i] ); // no & operator here
Array expressions “decay” to pointer expression under most circumstances, so you don’t need the & operator here.
Alternately, you can declare an array of pointers to char, like
char *name[NUMBER_OF_STRINGS];
and then allocate memory for each string as you read it:
char buffer[MAX_STRING_LENGTH+1];
...
scanf( “%s”, buffer );
student.name[i] = malloc( strlen( buffer ) + 1 );
if ( student.name[i] )
strcpy( student.name[i], buffer );
You just need to remember to free each student.name[i] when you’re finished.
The student name is a singular array of char and needs to be an array of character arrays.
struct students {
char name[20][40];
int score[20];
} student;
I arbitrarily assumed 40 characters per name was sufficient.
The scanf for the name needs to be changed from:
scanf("%s", &student.name[i]);
To:
scanf("%s", student.name[i]);
scanf("%s", &student.name[i]); You're addressing a single char from the string you declared. I assume you would want an individual object for every student. To do this my advice would be to define your struct like this:
typedef struct students {
char name[20];
int score;
}Student;
With this you have defined a new data type called Student. Each object of the type Student has a string called name and an int resembling the score.
After you've created this model, you can treat it as just another variable type, e.g. the following is totally valid:
Student student1, student2;
Alternatively, you could create an array of Students: Student group[20] and then have a loop fill it with data:
for(int i = 0; i < n; i++){
puts("Name of the student: ");
fgets(group[i].name, 20, stdin);
puts("Score of the student: ");
scanf("%d", &group[i].score);
}
The deal is per iteration to refer to an individual object of the array of students.
Also, I would strongly recommend to use fgets() or at least gets_s() for inputting strings. scanf() has multiple problems, some of which are that it stops input if it encounters a space, tab or a newline and most importantly it doesn't check for array bounds. Consider using a safer variant, just keep in mind that fgets() appends a '\n' before the terminating null.

I can't seem to print out a string from a structure but I can print an integer

My code is suppose to get the names of students and the student grade. After that I try to print the student names from the structure that I made and I can only get the grade to print. I get an error when trying to print the string using
printf("%s", test[0].names);
and the error says,
Unhandled exception at 0x0fe113af (msvcr100d.dll) in StudentNamesAndGrades.exe: 0xC0000005: Access violation reading location 0x65736f4a.
But when I use
printf("%d", test[0].studentScores);
It prints out the score of the first student. Here is the entire code because it might be something other than the way I'm trying to print it out.
#include <stdio.h>
#include <string>
/*
this program will get a name of students
and then you will enter the grade for each one :)
*/
struct students
{
char *names;
int studentScores;
};
int main(void)
{
int numStudents = 0;
students *test;
int i;
printf("Enter the number of students in your class: ");
scanf("%d", &numStudents);
test = (students*)malloc(numStudents * sizeof(students));
printf("Enter the names of the %d students\n", numStudents);
for (i = 0; i < numStudents; i++)
{
printf("Enter the name of student %d: ", i + 1);
scanf("%s", &test[i].names);
printf("Enter the students score: ");
scanf("%d", &test[i].studentScores);
}
printf("%d", test[0].studentScores);
printf("%s", test[0].names); // This is where I get a problem :/
return 0;
}
You did not allocate memory for char *names; while taking input at all.
Your struct could be like:
typedef struct students
{
char names[30];
int studentScores;
}students;
Also using fgets is safer than using scanf.
You need to allocate space for the names field, but I would recommend a different approach
struct students
{
char names[100];
int studentScores;
};
and then change the scanf() to
scanf("%99s", test[i].names);
there is another mistake in your first scanf() your are passing the address to the pointer, instead of the pointer.
You should use the address of & operator for the integer, because you need to pass a pointer to an integer for the "%d" specifier, but your names field variable was already a pointer, so no neet to take it's address.
Some other tips you might be interested in
Don't cast the result of malloc, although it seems that you are erroneously using a c++ compiler to compile c code, and in c++ you do need the cast, in c you don't, it makes your code harder to read and other problems which you can read with the most popular c question on Stack Overflow.
Check the return value from malloc, it doesn't matter how unlikely it could fail, since it could theoretically fail, you must check it's return value, which is NULL on failure.

Assign value to char * from ScanF

Can someone please help me understand why when I try to print out the value of student_name, it only returns null? I'm implementing a basic hashtable in C to store the a students name, id, and 2 tests. Everything else is storing correctly, I just can't manage to save the the student_name no matter what I try. I have two structs, the hashtable itself and then record, the elements I intend to put inside of the table. The character string will never be longer than 18 characters.
int main(){
char op[1];
int stu_id[1];
int exam1[1];
int exam2[1];
char * student_name = (char*)malloc(18*sizeof(char));
struct hashtable * dictionary = malloc(sizeof(struct hashtable));
dictionary->size = 13;
dictionary->table = malloc(13*sizeof(struct record *));
if(dictionary==NULL||dictionary->table==NULL){
printf("Unable to allocate memory for the dictionary.\n");
return;
}
int i;
int s = 13;
while(i<s){
dictionary->table[i]=NULL;
i++;
}
while(scanf("%s %d %d %d %s", op, stu_id, exam1, exam2, student_name) !=EOF){
if(*op=='i'){
printf("Intializing %s\n", *student_name);
add_item(dictionary, stu_id[0], exam1[0], exam2[0], student_name);
}
free(dictionary);
free(student_name);
return 0;
}
Remember that a string always have to contain a special terminator character ('\0'). This means that a string of length one (like your op array) is actually two characters.
This means that when you read into op you are actually writing beyond the bounds of the array, leading to undefined behavior. You either need to increase the size of op (to at least two), or declare it as a single char (i.e. not an array) and use the '%c' format code to read a single character.
Also, don't declare the integer variables as arrays, use the address-of operator & when calling scanf instead:
char op;
int stu_id;
int exam1;
int exam2;
/* ... */
scanf("%c %d %d %d %s", &op, &stu_id, &exam1, &exam2, student_name)
You also should not check the return value of scanf against EOF, in case the input is not formatted correctly. Compare it agains the number of values you want scanned, five in your case.
I suppose you are allocating memory for student record inside add_item() and assigning them to the dictionary->table. From the code you have posted, you are allocation memory to hold pointers to struct student record and not for the records themselves.
You need to free memory allocated for "dictionary->table" at the end of main().

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.

segmentation fault in C

I am trying to write this code, but it gives me segmentation fault after running the program, could you please help to sort it out?
#include <stdio.h>
#include <string.h>
typedef struct{
int salary;
char* name;
} employee ;
int main(){
employee p[2];
int i;
for(i=0;i<2; i++){
printf("enter sal ");
scanf("%d", &p[i].salary);
printf("enter name ");
scanf("%s", &p[i].name);
}
for(i=0;i<2; i++){
printf("p %d",p[i].salary);
printf("p %s",p[i].name);
}
return 0;
}
You need to allocate memory for the name field: p[i].name = (char*)malloc(MAX_NAME_LEN)
Also, the scanf("%s", &p[i].name) should read scanf("%s", p[i].name).
The structure field name is just a wild character pointer.
char* name;
you are reading the user input as:
scanf("%s", &p[i].name);
into the memory pointed by name which could be anywhere.
To fix this you need to dynamically allocate memory pointed to by name or you can change name to a char array of size one greater than the max length of the name possible.
char name[MAX];
You don't need the & operator when scanf'ing to pointer. And you need to malloc p[i].name
scanf("%s", p[i].name);
You are not allocating memory for char* name. change your data structure to
typedef struct
{
int salary;
char name[50];
}
or allocate memory using malloc
You forgot to allocate memory for p[i].name.
You have to reserve memory for the name member of each instance of employee:
p[i].name = (char*)malloc(expected_max_size);
just before the scanf for that variable. Declaring a pointer to char char* does not assign memory for the actual string pointed to, but just for the pointer itself, and in your example it is not initialized. By using malloc you reserve a piece of memory and makes the pointer point to it. You have to be careful with bounds checking, because you have to reserve the memory beforehand, enough to hold what the user is writing.
You need to allocate memory for the "name" string in your structure. Do this using malloc() or by declaring name as an array of a given size (char name[SIZE]).

Resources