Segmentation fault when writing data to a dynamic array - c

My assignment is to write a file that displays an unknown number of records entered by the user. Each record has the following fields: First Name, Last Name, Address, City, State, Zip Code, and Phone Number.
I assumed the best way to do this would be to define a struct Record with the fields above, then declare an array of Records that would contain as many records as the user entered. To accomplish this I would use a loop to get the inputs for each field per record, then if the user wanted to continue dynamically allocate an extra space in the Record array and continue until the user enters no. I encountered an access violation writing location error at line:
scanf("%s", records[i]->fname);
What's wrong with my code?
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct Record;
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
int zipcode;
int phoneNumber;
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = 'y';
int size = 1;
int i = 0;
struct Record **records;
records = malloc(sizeof(*records)*(size));
while(answer == 'y' || answer == 'Y')
{
printf("First Name: \n");
scanf("%s", records[i]->fname);
printf("Last Name: \n");
scanf("%s", records[i]->lname);
printf("Address: \n");
scanf("%s", records[i]->address);
printf("City: \n");
scanf("%s", records[i]->city);
printf("State: \n");
scanf("%s", records[i]->state);
printf("Zipcode: \n");
scanf("%d", records[i]->zipcode);
printf("Phone Number: \n");
scanf("%d", records[i]->phoneNumber);
//stores all record info
printf("Are there anymore records? [y/n] ");
answer = getchar();
if(answer == 'y' || answer == 'Y')
{
size++;
records[i++];
printf("\n");
}
records = realloc(records,sizeof(*records)*(size));
}
//open file
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL)
{
if(fwrite(records,sizeof(*records),size,fileWriter) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
exit(1);
}
fclose(fileWriter);
}
else
{
printf("Error opening file.");
}
}
EDITED VERSION
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
int zipcode;
int phoneNumber;
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = 'y';
int size = 1;
int i = 0;
struct Record *records = NULL;
struct Record *records_temp;
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = realloc(records,(size)*sizeof(*records));
if(records_temp == NULL)
{
free(records);
}
records = records_temp;
printf("First Name: \n");
scanf("%s", records[i].fname);
printf("Last Name: \n");
scanf("%s", records[i].lname);
printf("Address: \n");
scanf(" %[^\n]", records[i].address);
printf("City: \n");
scanf("%s", records[i].city);
printf("State: \n");
scanf("%s", records[i].state);
printf("Zipcode: \n");
scanf("%d", &records[i].zipcode);
printf("Phone Number: \n");
scanf("%d", &records[i].phoneNumber);
//stores all record info
printf("Are there anymore records? [y/n] ");
answer = getchar();
if(answer == 'y' || answer == 'Y')
{
size++;
records[i++];
printf("\n");
}
//open file
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL)
{
if(fwrite(records,sizeof(*records),size,fileWriter) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
exit(1);
}
fclose(fileWriter);
}
else
{
printf("Error opening file.");
}
}
}

Well, you get a segfault because you haven't allocated memory for the first entity in your records.
So to resolve that you need to
records[size-1] = malloc(sizeof(Records));
To put it in this way:
You have records that is a pointer to a pointer to Records.
When you did
records = malloc(sizeof(*records)*(size));
You actually asked for size pointers to Records.
But that is not enough, you need to allocate another memory to store the actual Records so that is why we have to
records[size - 1] = malloc(sizeof(Records));
Note: if size > 1 then you should do:
int i = 0;
for(;i < size; i++) {
records[i] = malloc(sizeof(Records));
}
In addition to that, why did you go with Records **, as Arjun has already explained, you should use Records * and fix the part of realloc-ing new memory, because if realloc fails, it returns NULL and you end up with memory leak or another segfault in the worst scenario, either way -- it is not good for your program.
Please see Arjun's post

When you want to dynamically allocate space for a list of Records, you should be doing:
struct Record *records;
records = malloc(size * sizeof(*records));
This allocates space for size number of Records.
To increment the allocated size, you should:
struct Record *records_temp = realloc(records, newsize * sizeof(*records));
if (records_temp == NULL) {
free(records);
/* die with error -ENOMEM */
}
records = records_temp;
Do not realloc to the same pointer. It can cause you to leak memory on failure.
Or, you can avoid malloc() and use just realloc() in a loop by providing it with a NULL pointer initially.
C 89 standards says:
4.10.3.4 The realloc function
If ptr is a null pointer, the realloc function behaves like the malloc
function for the specified size.
struct Record *records = NULL;
struct Record *records_temp;
size = INITIAL_SIZE;
while (/* your condition */) {
records_temp = realloc(records, size * sizeof(*records));
if (records_temp == NULL) {
free(records);
/* die with error -ENOMEM */
}
records = records_temp;
/* do stuff */
size += SIZE_INCREMENT;
}

As Jonathan Leffler commented, but declined to make an answer out of his comments:
Note that the line records[i++]; increments i and does nothing else useful.
And also:
Also note that the struct Record; line really isn't necessary. The only time it might make a difference is if you are defining mutually recursive structures in a function scope rather than at file scope (and this use is at file scope). As it is, the line says "there is a type struct Record", and the next block of code says "there is a type struct Record and this is how it is defined".
When asked by Cool Guy to illustrate what was meant by that, Jonathan said:
struct A { … };
struct B { … };
void f(void)
{
struct A;
struct B
{
…;
struct A *a_ref;
…
};
struct A
{
…;
struct B *b_ref;
…
};
…
}
Without the struct A; line, the a_ref element would point at a structure of the externally defined type struct A, not the mutually recursive pair of structure types. The error messages could be quite confusing too! However, reusing type names like this is a bad idea.

Related

C structures displaying numbers rather than user data

Kindly help me debug this code. It is not displaying the correct data. The following program is supposed to get book details from the user, dynamically allocate memory to them and display them.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "problem5.h"
int main()
{
struct books *b;
b = (struct books*)malloc(sizeof(struct books));
int command, flag = 0;
int n=0, i;
while(flag == 0)
{
printf ("1. Add Book\n");
printf ("2. View Books\n");
printf ("3. Quit\n");
scanf("%d", &command);
if (command == 1)
{
printf ("Enter Name\n");
//scanf("%d", &(b+i)->name);
scanf(" ");
gets((b+i)->name);
printf ("Enter Author\n");
//scanf("%d", &(b+i)->author);
scanf(" ");
gets((b+i)->author);
printf ("Enter Year Published\n");
scanf("%d", &(b+i)->year_published);
n=n+1;
i=n;
} else if (command == 2)
{
for(i=0; i<n; i++)
{
printf ("%d - %d by %d\n", (b+i)->year_published, (b+i)->name, (b+i)->author);
}
} else if (command == 3)
{
flag = 1;
} else
{
printf ("Invalid choice!\n");
}
}
}
The following is problem5.h header file that has the structure books. Initially I didn't declare the variables in array since I didn't want to use much memory. But I had to due to many errors.
#define PROBLEM3_H_INCLUDED
typedef struct books{
char *name[30];
char *author[30];
int year_published;
};
#endif // PROBLEM3_H_INCLUDED
When I print I am getting random numbers instead of the data the user entered.
The overall design of your code is wrong.
This is basically what you want.
I made following changements:
using meaningful variable names
changed struct book so the structure can contain one book. Also renamed it from struct books to struct book because the structure contains only one book.
allocating memory properly
using books[numberofbooks].x instead of the less readable *(books + numberofbooks)->x
More explanations in the comments.
#include <stdio.h>
#include <stdlib.h>
struct book {
char name[30];
char author[30];
int year_published;
};
int main()
{
struct book* books = NULL; // no books at all initially so we
// initialize to NULL
// so we can simply use realloc
int numberofbooks = 0;
int programend = 0;
while (programend == 0)
{
printf("1. Add Book\n");
printf("2. View Books\n");
printf("3. Quit\n");
int command;
scanf("%d", &command);
if (command == 1)
{
getchar(); // consume Enter key (due su scanf)
// allocate memory for one more book
books = realloc(books, sizeof(struct book) * (numberofbooks + 1));
printf("Enter Name\n");
gets(books[numberofbooks].name);
printf("Enter Author\n");
gets(books[numberofbooks].author);
printf("Enter Year Published\n");
scanf("%d", &books[numberofbooks].year_published);
numberofbooks++; // increment number of books
}
else if (command == 2)
{
for (int i = 0; i < numberofbooks; i++)
{
printf("%d - %s by %s\n", books[i].year_published, books[i].name, books[i].author);
}
}
else if (command == 3)
{
programend = 1;
}
else
{
printf("Invalid choice!\n");
}
}
}
There is still room for improvement though:
error checking for realloc
error checking for interactive I/O
not using the deprecated and dangerous gets
and certainly a few other things
b = (struct books*)malloc(sizeof(struct books));
Here, you are allocating memory for only one instance of struct books , But you are accessing multiple instances of struct books.
printf ("%d - %d by %d\n", (b+i)->year_published, (b+i)->name, (b+i)->author);
For i>=1 (b+i) is not defined, because you did not allocate memory for it. You have allocated memory for only (b+0).
int n=0, i;
gets((b+i)->name);
Here, i has not been initiliazed.

How do I add a contact to a phonebook program in C?

For my intro to programming class, we have to code a phonebook in C that lets users add contacts, as well as delete and display them. It also has to allocate and free memory as necessary (I tried to do this, but I honestly don't really know what I'm doing).
Anyway, I cannot figure out how to add a contact to the phonebook. I've pasted the relevant part of the program so far. It compiles, but it crashes every time I try to add a contact. Once I get this figured out, I think I can get the rest of the functions without too much trouble. If anyone could help me out, I'd really appreciate it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct entry {
char fname[20];
char lname[20];
char pnumber[20];
} entry;
// function prototypes
void addentry(int, entry*, char addfname[20], char addlname[20], char addpnumber[20]);
main() {
int selection = 0;
int inputtest = 1;
int pnum = 0; // keeps track of number of contacts
char addfname[20] = { '\0' };
char addlname[20] = { '\0' };
char addpnumber[20] = { '\0' };
entry *pcontacts;
pcontacts = (entry*)calloc(1, (sizeof(entry)));
if (pcontacts == NULL) {
printf("No memory is available.");
free(pcontacts);
return 0;
}
while (1) {
do {
printf("\nPhonebook Menu\n\n");
printf("1:\tAdd contact\n");
printf("2:\tDelete contact\n");
printf("3:\tDisplay contacts\n");
printf("4:\tExit\n");
printf("\nChoose an action (1-4): ");
scanf("%d", &selection);
if (selection < 1 || selection > 4) {
printf("Invalid input. Please enter an integer between 1 and 4.\n");
inputtest = 0;
}
if (selection == 4) {
free(pcontacts);
printf("\nThank you for using this phonebook.");
return 0;
}
switch (selection) {
case 1:
pnum++;
printf("\nEnter first name: ");
scanf("%s", addfname);
printf("Enter last name: ");
scanf("%s", addlname);
printf("Enter phone number (no spaces): ");
scanf("%s", addpnumber);
addentry(pnum, pcontacts, addfname[20], addlname[20], addpnumber[20]);
break;
}
} while (inputtest == 1);
}
}
void addentry(int pnum, entry *pcontacts, char addfname[20], char addlname[20], char pnumber[20]) {
pcontacts = (entry*)malloc(pnum * (sizeof(entry)));
if (pcontacts != NULL) {
strcpy(*pcontacts[pnum - 1].fname, addfname);
printf("\nContact has been added.");
} else {
printf ("No memory is available.\n");
}
}
You get strings from standard input with scanf, but you should tell scanf the maximum number of bytes to store to the destination arrays to avoid buffer overruns:
scanf("%19s", addfname);
...
scanf("%19s", addlname);
...
scanf("%19s", addpnumber);
The way you call addentry is incorrect:
addentry(pnum, pcontacts, addfname[20], addlname[20], addpnumber[20]);
You actually try to read the byte just after the end of addfname, addlname and addpnumber. You should instead pass the arrays themselves, that will be passed to the function addentry as pointers to their first bytes:
addentry(pnum, pcontacts, addfname, addlname, addpnumber);
addentry should reallocate the array with realloc. It should be passed a pointer to the array pointer to it can update the pointer in main.
addentry does not copy the strings correctly: it only copies one, but with a syntax error.
Here is a corrected version:
void addentry(int, entry**, char addfname[20], char addlname[20], char addpnumber[20]);
int main(void) {
int selection = 0;
int inputtest = 1;
int pnum = 0; // keeps track of number of contacts
char addfname[20];
char addlname[20];
char addpnumber[20];
entry *pcontacts = NULL;
for (;;) {
do {
printf("\nPhonebook Menu\n\n");
printf("1:\tAdd contact\n");
printf("2:\tDelete contact\n");
printf("3:\tDisplay contacts\n");
printf("4:\tExit\n");
printf("\nChoose an action (1-4): ");
scanf("%d", &selection);
if (selection < 1 || selection > 4) {
printf("Invalid input. Please enter an integer between 1 and 4.\n");
inputtest = 0;
}
if (selection == 4) {
free(pcontacts); /* OK for NULL */
printf("\nThank you for using this phonebook.");
return 0;
}
switch (selection) {
case 1:
printf("\nEnter first name: ");
scanf("%19s", addfname);
printf("Enter last name: ");
scanf("%19s", addlname);
printf("Enter phone number (no spaces): ");
scanf("%19s", addpnumber);
addentry(pnum, &pcontacts, addfname, addlname, addpnumber);
pnum++;
break;
}
} while (inputtest == 1);
}
}
/* add an entry at position pnum */
void addentry(int pnum, entry **pp, char addfname[20], char addlname[20], char pnumber[20]) {
entry *pcontact = *pp;
pcontacts = realloc(pcontacts, (pnum + 1) * sizeof(entry));
if (pcontacts != NULL) {
*pp = pcontacts; /* update pointer in main */
strcpy(pcontacts[pnum].fname, addfname);
strcpy(pcontacts[pnum].lname, addlname);
strcpy(pcontacts[pnum].pnumber, addpnumber);
printf("\nContact has been added.");
} else {
printf ("No memory is available.\n");
}
}

Why is my file output overwritten?

My program takes user input and stores it in an array of Records that I've defined as a structure: struct Record.
The user input is are the fields of the struct. Everything complies error free, but it seems I can't get the formatting correct. My program keeps asking for user input until the user enters 'n' when asked if there are anymore records.
Once there are no more records the program loops through the created records and file prints each of them spaced out by tabs and at the end starting with a newline for the next record. However, instead of starting at a new line and printing another record in the same fashion, it overwrites the previous record printed and tabs the next one even further.
What causes this to happen?
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
char zipcode[51];
char phoneNumber[51];
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = 'y';
int size = 1;
int i = 0;
struct Record *records;
struct Record *records_temp = NULL;
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = calloc((size),sizeof(*records));
records = records_temp;
printf("First Name: \n");
scanf("%s", records[size-1].fname);
printf("Last Name: \n");
scanf("%s", records[size-1].lname);
printf("Address: \n");
scanf(" %[^\n]", records[size-1].address);
printf("City: \n");
scanf("%s", records[size-1].city);
printf("State: \n");
scanf("%s", records[size-1].state);
printf("Zipcode: \n");
scanf("%s", records[size-1].zipcode);
printf("Phone Number: \n");
scanf("%s", records[size-1].phoneNumber);
//stores all record info
printf("Are there anymore records? [y/n] ");
scanf(" %c", &answer);
if(answer == 'y' || answer == 'Y')
{
size++;
printf("\n");
}
}
//open file
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL)
{
for(;i< size; i++)
{
fprintf(fileWriter,"%s\t",records[i].fname);
fprintf(fileWriter,"%s\t",records[i].lname);
fprintf(fileWriter,"%s\t",records[i].address);
fprintf(fileWriter,"%s\t",records[i].city);
fprintf(fileWriter,"%s\t",records[i].state);
fprintf(fileWriter,"%s\t",records[i].zipcode);
fprintf(fileWriter,"%s\n",records[i].phoneNumber);
}
free(records);
fclose(fileWriter);
}
else
{
printf("Error opening file.");
}
}
I changed a little bit your code, but I think you should use linked list as a data structure here, it's more simple and consume less memory.
I made some tries and all went ok. :)
Hope that help you!!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct Record Record;
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
char zipcode[51];
char phoneNumber[51];
Record *next;
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = '\0';
// int size = 1;
// int i = 0;
Record *records = NULL;
Record *records_first = NULL;
Record *records_previous = NULL;
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL) {
for( ; ; ) {
records = (Record*) malloc(sizeof(Record));
if(records_first == NULL)
records_first = records;
if(records_previous != NULL)
records_previous->next = records;
records = records_first;
printf("First Name: \n");
scanf("%s", records->fname);
fprintf(fileWriter,"%s\t",records->fname);
printf("Last Name: \n");
scanf("%s", records->lname);
fprintf(fileWriter,"%s\t",records->lname);
printf("Address: \n");
scanf(" %[^\n]", records->address);
fprintf(fileWriter,"%s\t",records->address);
printf("City: \n");
scanf("%s", records->city);
fprintf(fileWriter,"%s\t",records->city);
printf("State: \n");
scanf("%s", records->state);
fprintf(fileWriter,"%s\t",records->state);
printf("Zipcode: \n");
scanf("%s", records->zipcode);
fprintf(fileWriter,"%s\t",records->zipcode);
printf("Phone Number: \n");
scanf("%s", records->phoneNumber);
fprintf(fileWriter,"%s\t\n\n",records->phoneNumber);
records->next = NULL;
records_previous = records;
printf("Are there anymore records? [y/n] ");
scanf(" %c", &answer);
if(tolower(answer) != 'y') {
free(records);
fclose(fileWriter);
break;
}
}
} else
printf("Error opening file.");
return 0;
}
Open the file with additional a mode as in "append". I think there is no need for further explanation what that would be good for, right?
However, the actual problem seems that you overwrite the pointer to the previous record already in the input loop. How is that supposed to work? Just go through that loop and try to follow the instructions as the program would do.
Problem is you cannot do it like this. Use a linked list for the allocated blocks.
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = calloc((size),sizeof(*records));
records = records_temp;
...
}
Did you perhaps mean this?
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = realloc(records, size * sizeof *records);
if (records_temp == NULL)
{
/* Handle allocation error */
}
records = records_temp;
/* ... */
}
Do not confuse calloc with realloc. Read the manuals if you need further clarification.
Don't forget to initialise records to NULL...
If your concern is optimisation, the most significant bottleneck here will be your file input/output. That's unavoidable, and aside from researching setvbuf there isn't much you can do about it. The next bottleneck will be underlying calls to kernel allocation functions. You can reduce that bottleneck by calling allocation functions less. For example, you could grow your array by doubling its size each time rather than by adding 1:
size_t size = 0;
int answer;
do {
size_t index = size++;
if ((index & size) == 0) {
void *temp = realloc(array, (2 * index + 1) * sizeof *array);
if (temp == NULL) {
/* Handle allocation error */
}
array = temp;
}
puts("First Name:");
scanf("%s", array[index].fname);
/* snip */
answer = getchar();
} while (answer != EOF && tolower(answer) == 'y');
Alternatively, you could reinvent the wheel and perform the same work that realloc performs behind the scenes (and possibly lose some benefit of optimisation), by adding calls to memcpy and free to your code like so:
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = calloc((size),sizeof(*records));
if (records_temp == NULL)
{
/* Handle allocation error */
}
if (records != NULL)
{
memcpy(records_temp, records, (size - 1) * sizeof *records);
free(records);
}
records = records_temp;
/* ... */
}
P.S. In case you missed it the first time: Don't forget to initialise records to NULL...
The biggest problem I see is memory allocation logic. The first time through the loop, you allocate memory for 1 record and increment size. The second time through the loop, you allocate memory for 2 more records, because size == 2. The third time through the loop, you allocate memory for 3 more records, for a total of 1+2+3=6.
That answers why it's happening. Olaf's suggested fix, linked list, is a good one.

Using pointer in structure and writing it file in C

I was working on my college project in C and got some problem.
I used pointer to structure and used it to write in a file using fwrite but it isn't helping.Here is the code I used.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#include<conio.h>
struct collection{
char *fname, *lname, *telephone, *address, *seat;
};
collection * alloc( ){
struct collection *r = (struct collection *) malloc (sizeof(collection*));
r->fname = NULL;
r->lname = NULL;
r->telephone = NULL;
r->address = NULL;
r->seat = NULL;
return (r);
}
void string_realloc_and_copy (char **dest, const char *src){
*dest =(char *) realloc (*dest, strlen (src) + 1);
strcpy (*dest, src);
}
int main(){
char ch = 'Y', temp[50];
FILE *ptf;
struct collection *asd;
asd = alloc();
//printf("%d",sizeof(asd));
//opening file
ptf = fopen("lang.txt","w+");
do{
printf("First name: ");
gets(temp);
string_realloc_and_copy(&asd->fname,temp);
printf("Last name: ");
gets(temp);
string_realloc_and_copy(&asd->lname,temp);
printf("Telephone: ");
gets(temp);
string_realloc_and_copy(&asd->telephone,temp);
printf("Address: ");
gets(temp);
string_realloc_and_copy(&asd->address,temp);
printf("Seat you want to book: ");
gets(temp);
string_realloc_and_copy(&asd->seat,temp);
fwrite(asd,12*sizeof(collection),1,ptf);
fflush(ptf);
//fprintf(ptf,"\n");
printf("Do you wish to enter another data...? (Y/N) ");
ch = getch();
}while((ch=toupper(ch))== 'Y');
rewind(ptf);
while(fread(asd,12*sizeof(collection),1,ptf) == 1){
printf("\n\n%s",asd->fname);
printf("\n\n%s",asd->lname);
printf("\n\n%s",asd->telephone);
printf("\n\n%s",asd->address);
printf("\n\n%s",asd->seat);
}
fclose(ptf);
}
It works until asd->telephone is reached it ask for address and goes unresponding. I could not figure out what i did wrong. I thought it was out of memory so i change
struct collection *r = (struct collection *) malloc (sizeof(collection*));
to
struct collection *r = (struct collection *) malloc (12*sizeof(collection*));
And it worked for some time and again same thing happened. I am using devC++ for compilation. Thanks in advance;
First you should not use gets() because its deprecated and there is no limit in how many characters it gets from stdin. I recommand you to use fgets. You should use malloc like this for a pointer
malloc(sizeof(*collection));
This way you allocate memory for a pointer.
And one another thing try this program with putc() and see if it works.
malloc (sizeof(collection*)) should be malloc(sizeof(*collection)). Your code is only allocating enough space for a pointer to the collection type, not the size of the structure that the collection pointer points to.
This also shows why it's a bad idea to use the same name for both a variable and a type. If you'd used different names, you would have gotten an error from the compiler. Use collection_t for the type.
Try sizeof (struct collection) without the *
i found so many changes in your code.First change is struct collection instead of collection .Second change is i used two file descriptors one for reading another one for writing.Third in your code you are initializing "asd" only once due to this it will write same structure every time into file . So i initialized inside do-while loop.Fourth one i used scanf instead of gets because when you are taking multiple inputs it's skipping some inputs.Fifth i removed 12 form fwrite and fread.Sixth i used one more getchar because we will press enter after giving seat number so ch is taking that enter to take the user input i had to use one more getcharFinally the changed code is
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
//#include<conio.h>
struct collection
{
char *fname, *lname, *telephone, *address, *seat;
};
struct collection *alloc( ){
struct collection *r= malloc(sizeof(struct collection));
r->fname = NULL;
r->lname = NULL;
r->telephone = NULL;
r->address = NULL;
r->seat = NULL;
return (r);
}
void string_realloc_and_copy (char **dest, const char *src){
*dest =(char *) realloc (*dest, strlen (src) + 1);
strcpy (*dest, src);
}
int main(){
char ch = 'Y', temp[50];
FILE *ptf;
struct collection *asd;
//printf("%d",sizeof(asd));
//opening file
ptf = fopen("lang.txt","wb");
do{
asd = alloc();
printf("First name: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->fname,temp);
printf("Last name: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->lname,temp);
printf("Telephone: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->telephone,temp);
printf("Address: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->address,temp);
printf("Seat you want to book: ");
scanf("%s",temp);
string_realloc_and_copy(&asd->seat,temp);
fwrite(asd,sizeof(struct collection),1,ptf);
fflush(ptf);
//fprintf(ptf,"\n");
printf("Do you wish to enter another data...? (Y/N) ");
ch = getchar();
ch = getchar();
}while((ch=toupper(ch))== 'Y');
//rewind(ptf);
fclose(ptf);
FILE *ptf1;
ptf1 = fopen("lang.txt","rb");
while(fread(asd,sizeof(struct collection),1,ptf1)){
printf("\n\n%s",asd->fname);
printf("\n\n%s",asd->lname);
printf("\n\n%s",asd->telephone);
printf("\n\n%s",asd->address);
printf("\n\n%s",asd->seat);
}
fclose(ptf1);
}
and sample out put is

C struct field assignment overwrites another field

I am writing a fantasy football draft program for fun.
I encountered a strange problem. I assign a value to a struct field and that happens, but it also assigns that value to another field in the struct. Apologies for the messy debugging printf statements.
I clearly don't understand something about struct field assignment.
code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
int QB_count = 0;
int RB_count = 0;
int WR_count = 0;
int TE_count = 0;
int DEF_count = 0;
struct Player {
char *name;
char *position;
int age;
int bye_week;
};
int get_name (struct Player *drafted) {
char name[20];
fputs("Enter Player Name: ", stdout);
fflush(stdout);
if (fgets(name, sizeof name, stdin) != NULL){
char *newline = strchr(name, '\n');
if (newline != NULL){
*newline = '\0';
}
drafted->name = name;
printf("You've drafted: %s\n", drafted->name);
}
return 0;
}
int get_position(struct Player *drafted){
char position[20];
int depth;
char *nametemp = drafted->name;
printf("nametemp: %s\n", nametemp);
fputs("Enter Player Position in 'QB/RB/WR/TE/DEF' format: ", stdout);
fflush(stdout);
if (fgets(position, sizeof position, stdin) != NULL){
char *newline = strchr(position, '\n');
if (newline != NULL){
*newline = '\0';
}
drafted->position = position;
if (strcmp(position, "QB") == 0){
QB_count++;
depth = QB_count;
} else if (strcmp(position, "RB") == 0){
RB_count++;
depth = RB_count;
} else if (strcmp(position, "WR") == 0){
WR_count++;
depth = WR_count;
} else if (strcmp(position, "TE") == 0){
TE_count++;
depth = TE_count;
} else if (strcmp(position, "DEF") == 0){
DEF_count++;
depth = DEF_count;
} else {
printf("Please re-enter position information using the format 'QB' or 'qb'\n");
get_position(drafted);
return 0;
}
drafted->name = nametemp;
printf("NAME: %s\n", drafted->name);
printf("You've drafted %s at: %s%d\n", drafted->name, drafted->position, depth);
}
return 0;
}
int get_age (struct Player *drafted){
return 0;
}
int get_bye_week (struct Player *drafted){
return 0;
}
int main (){
int stop = 0;
char text[20];
while (TRUE){
struct Player drafted;
printf("Welcome to the 2012 Draft Day Program\n");
get_name (&drafted);
printf("NAME_MAIN: %s\n", drafted.name);
get_position(&drafted);
printf("You've drafted %s at: %s\n", drafted.name, drafted.position);
get_age(&drafted);
get_bye_week(&drafted);
fputs("Would you like to draft another player?\n"
"Enter '1' for no, '0' for yes\n", stdout);
fflush(stdout);
if(fgets(text, sizeof text, stdin)){
int number;
if (sscanf(text, "%d", &number) == 1){
if (number == 1){
printf("Draft Ended!\n");
break;
}
}
}
}
return 0;
}
The resulting output is:
Welcome to the 2012 Draft Day Program
Enter Player Name: Aaron Rodgers
You've drafted: Aaron Rodgers
NAME_MAIN: Aaron Rodgers
nametemp: Aaron Rodgers
Enter Player Position in 'QB/RB/WR/TE/DEF' format: QB
NAME: QB
You've drafted QB at: QB1
You've drafted QB at: QB
Would you like to draft another player?
Enter '1' for no, '0' for yes
1
Draft Ended!
Why does drafted.name become "QB"?
In your get_name function you're assigning to the name field of your struct Player a stack variable name.
In this line:
drafted->name = name;
name is declared in the function and so it's scope is limited to that function. Once get_name returns, the variable goes out of scope, and attempts to use that memory invoke undefined behavior.
Instead of using the simple assignment, you need to allocate space for drafted->name using malloc, and use strncpy to make a copy of the name. If strdup is available, you can use that to allocate the space and do the copy in a single step. Alternately, you could allocate space for drafted->name before reading the name, and use it in place of the name variable.
As a final option, if you assume a maximum length for names - your current code allows names up to a string length of 19 - you can simply declare an array of that size for each struct Player:
struct Player
{
char name[NAME_MAXLEN];
You have an identical problem with your position field in the get_position function.

Resources