Using pointer in structure and writing it file in C - 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

Related

Pointer to structure in C

How can I display the stored values via pointer, my code outputs to NULL. I've already tried assigning the struct emp to ptr before the 2nd loop but it won't run.
struct rec {
char *Name;
}emp[100];
int main() {
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for(i=0; i!=x; i++){
printf("Enter Name: ");
scanf("%[^\n]", &ptr->Name);
getchar();
ptr++;
printf("\n");
}
i = 0;
while(i!=x){
printf("Name is: %s\n", *ptr->Name);
i++;
ptr++;
}
If the code iterates twice it prints
Name: (NULL)
Name: (NULL)
How can I display the stored values via pointer, my code outputs to NULL. I've already tried assigning the struct emp to ptr before the 2nd loop but it won't run.
There are several issues in your code which are listed below:
You need to re-initialize your ptr pointer to the beginning of the array emp after the first loop.
ptr = emp;
Second one being data member name of your struct emp. It is just a pointer and it doesn't point towards a valid memory address where you can save user input cstring. Either you need to allocate the memory dynamically using malloc or use statically allocated memory just like shown below. However, you can have buffer overflow if you input characters more than DEFAULT_NAME_SIZE (including /0 character).
%[^\n] matches a char *, not a char **. You need to use scanf("%[^\n]", ptr->Name); not scanf("%[^\n]", &ptr->Name);.
"%s" format specifier of printf requires an arugment of type char * but you have been passing char type to it. The correct statement is printf("Name is: %s\n", ptr->Name);.
-
#include <stdio.h>
#define DEFAULT_NAME_SIZE 200
struct rec {
char Name[DEFAULT_NAME_SIZE];
} emp[100];
int main()
{
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for (i=0; i< x; i++){
printf("Enter Name: ");
scanf("%[^\n]", ptr->Name);
getchar();
ptr++;
printf("\n");
}
ptr = emp;
for (i = 0; i < x; i++){
printf("Name is: %s\n", ptr->Name);
ptr++;
}
return 0;
}
You can try to enable all warning while you compile your code. Most of the bugs can be pointed by the compiler's warning message.
char *Name;
You never allocated space for the name. Did you mean
char Name[100]
?
This should work, until somebody enters too long of a name. You will get to buffer overflow later and learn about dynamic memory allocation.
When scanning or printing strings, we don't use & and * for referencing and dereferencing pointers, but we must also alloc and free space for them. Fixed your code:
#include <stdio.h>
#include <stdlib.h>
struct rec {
char *Name;
}emp[100];
int main() {
int x;
int i;
struct rec *ptr = NULL;
ptr = emp;
printf("Enter Number of Clients: ");
scanf("%d", &x);
getchar();
for(i=0; i!=x; i++)
{
printf("Enter Name: ");
/* alloc space for string pointer */
ptr->Name = (char*) malloc(sizeof(char)*10);
scanf("%s[^\n]",ptr->Name);
getchar();
ptr++;
printf("\n");
}
i = 0;
/* reset array pointer position */
ptr=emp;
while(i!=x)
{
printf("Name is: %s\n", (ptr->Name));
/* free space for string pointer */
free(ptr->Name);
i++;
ptr++;
}
}
PS: Remember resetting a pointer to the initial position whenever using pointers to arrays.

Segmentation fault when writing data to a dynamic array

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.

Segmentation fault and realloc(): invalid next size: [duplicate]

This question already has an answer here:
free char*: invalid next size (fast) [duplicate]
(1 answer)
Closed 8 years ago.
I have a program and gets information from the keyboard and puts them into a struct and then write the struct to a file.
However, when I'm reallocating memory for the second time it seems to fail for no reason. Also, if I enter more than 1 person's information, the program fails in the end with a seg fault. The program runs fine if I enter just 1 person's information.
Thanks.
// Program
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct person person;
struct person {
char fname[20];
char lname[20];
int num;
};
int main(void){
int size = 0;
int count = 0;
person* listofperson = NULL;
char answer = 'n';
FILE* myfile;
do{
char* buf = (char*)malloc(sizeof(char)*50);
printf("Please enter the person's first name: \n");
fgets(buf, 50, stdin);
if(count == size){
size += 2;
listofperson = (person*)realloc(listofperson, (size_t)(sizeof(person)*size));
}
strncpy((listofperson+count)->fname, buf, 50);
printf("Please enter the person's last name: \n");
fgets(buf, 50, stdin);
strncpy((listofperson+count)->lname, buf, 50);
printf("Please enter the person's number: \n");
fgets(buf, 50, stdin);
sscanf(buf, "%d", &((listofperson+count)->num));
free(buf);
count++;
printf("Do you want to enter another one?\n");
answer = getchar();
getchar();
}while(tolower(answer) != 'n');
myfile = fopen("myfile", "a");
for(int i = 0; i < count; i++){
fprintf(myfile, "%s", (listofperson+i)->fname );
fprintf(myfile, "%s", (listofperson+i)->lname );
fprintf(myfile, "%d\n", (listofperson+i)->num );
}
fclose(myfile);
myfile = NULL;
free(listofperson);
}
For one thing, the people who are saying that realloc() doesn't work with a NULL pointer aren't speaking the truth. The behavior is documented here for C++ and here for C, it just works like malloc() in the case of a NULL pointer passed. Although I would agree that it is bad practice to assign memory that way.
You are not checking for errors in your malloc() and realloc() calls, they are not guaranteed to succeed, so you shouldn't assume they will.
In this case you shouldn't name your point to a person node "list of people", as this convention may be confused with a linked list. I would strongly reccomend you attempt to implement a linked lists for this programming case, since that is basically how you are working with your data anyways. For a tutorial on linked lists, see this link.
You should change the name of the file in fopen() to include a .txt extension. Otherwise the system will not know what the file type is.
change
struct person {
char fname[20];
char lname[20];
int num;
};
to
struct person {
char fname[50];
char lname[50];
int num;
};
Which is too small, it's already pointed out by ouah. It is necessary to align the value of one.
The error message indicates that the memory is destroyed beyond the area secured.

collect string in loop and printout all the string outside loop

I'm newbie here and there is some question that I want have some lesson from you guys.
For example:
#include <stdio.h>
#include<stdlib.h>
#include<ctype.h>
void main()
{
char name[51],selection;
do
{
printf("Enter name: ");
fflush(stdin);
fgets(name,51,stdin);
printf("Enter another name?(Y/N)");
scanf("%c",&selection);
selection=toupper(selection);
}while (selection=='Y');
//I want to printout the entered name here but dunno the coding
printf("END\n");
system("pause");
}
As I know when the loops perform will overwrite the variable then how I perform a coding that will printout all the name user entered?
I have already ask my tutor and he is ask me to use pointer, can anyone guide me in this case?
You've basically got two options, create a list of all the names, looping through each of them at the end, or concatenate all the names into a string as you read them, and print that whole buffer at the end. The first goes roughly like this:
char ch[2]="Y", names[100][52]; //store up to 100 50-char names (leaving space for \n and \0)
int x, nnames=0;
while(nnames<100 && *ch=='Y'){
fgets(names[nnames++], sizeof names[0], stdin); //since names is a 2d array, look
//only at the length of a row, (in this case, names[0])
fgets(ch, 2, stdin);
*ch = toupper(*ch);
}
for(x=0; x<nnames; x++)
//print names[x].
And the second goes roughly like this:
char names[100*52], *np=names, *ep=names+sizeof names; //an array, the position, and the end
char ch[2]="Y";
while(np<ep && *ch=='Y'){
fgets(np, ep-np, stdin); //read a name, and a newline into the buffer
//note how I use the difference between the end and the position to tell
//fgets the most it can possibly read
np+=strlen(np); //advance the position to the end of what we read.
//same deal with the y/n stuff...
}
printf("%s", names);
Notice the lack of loop at the end, because the whole string is stored in names.
Use a single string to get all names:
char allnames[1000] = "";
do {
//get name in fgets
selection = toupper(selection);
strcat(allnames, selection);
//Check for repetion
} while (/*there is repetion*/);
printf("%s", allnames);
You've to select the size of allnames suitably to store all names.
You can use a linked list to store all the entered names. All data structure books talk about linked list a lot.
#include <stdio.h>
#include <stdlib.h>
struct name_node
{
char name[100];
struct name_node *next;
};
struct name_node* add_name(struct name_node *first, const char *name)
{
struct name_node *p;
/* create our node */
p = (struct name_node*)malloc(sizeof(struct name_node));
strcpy(p->name, name);
p->next = NULL;
/* link our node to the tail */
if (first) {
for (; first->next; first = first->next);
first->next = p;
}
return p;
}
void print_names(struct name_node *first)
{
/* print names stored in the list */
for (; first; first = first->next) {
printf("%s\n", first->name);
}
}
/* free the memory we used */
void destroy_list(struct name_node *first)
{
if (first) {
if (first->next)
destroy_list(first->next);
free(first);
}
}
int main(void)
{
struct name_node *head = NULL;
struct name_node *node;
char name[100];
char selection;
do {
printf("Enter name: ");
fflush(stdin);
fgets(name, 51, stdin);
/* save the user input to a linked list */
/* save head if we don't have head */
node = add_name(head, name);
if (!head)
head = node;
printf("Enter another name?(Y/N)");
scanf("%c", &selection);
selection = toupper(selection);
}
while (selection == 'Y');
/* print the list if we have any data */
if (head)
print_names(head);
/* free the memory we used */
destroy_list(head);
printf("END\n");
system("pause");
return 0;
}

problem at malloc

i'm trying to apply malloc in my code, but still having a problem, there's an error saying : "request for member 'id' in something not a structure or union".
what i want to do is to use malloc instead of array.. and store the structure in each indices, i tried array[i]->id, but bunch of garbage character stored on my text file. I also increment i and didn't use loop, coz user may only input once... this is my code:
#include<stdio.h>
#include<stdlib.h>
struct studentinfo{
char id[8];
char name[30];
char course[5];
}s1;
main(){
int i=0;
FILE *stream = NULL;
stream = fopen("studentinfo.txt", "a+");
struct studentinfo *array[50];
array[i] = (struct studentinfo*) malloc(sizeof(struct studentinfo));
printf("Enter Student ID: ");
scanf("%s", array[i].id);
fflush(stdin);
printf("Enter Student Name: ");
gets(array[i].name);
fflush(stdin);
printf("Enter Student Course: ");
scanf("%s", array[i].course);
fprintf(stream, "\n%s,\t%s,\t%s", array[i].id, array[i].name, array[i].course);
i++;
fclose(stream);
free(array);
getch();
}
hope you can help me... thanks in advance :)
You're accessing the properties incorrectly.
array[i]
is a pointer to a struct, so
array[i].id
is going to give you an error. Use
array[i]->id
to dereference.
You should initialize the array and free it like this: Am i using malloc properly?
Also... follow Zurahn's instruction.

Resources