Repeating strings but not ints when reading from files - c

I've written a function that uses fscanf("%s &d &d &d") to read from a file. For some reason, when I display the output, all the integer values are correct, but the strings are all the same. food_stuff is a struct held in an array.
*EDIT
I've tried using a for to add each element from one array to the other, and I've tried strcpy.
Here's the function.
int readFromFile()
{
char*name;
int type;
int cals;
int price;
FILE * food_file;
food_file = fopen ("food_file.txt", "r");
while(fscanf(food_file, "%s %d %d %d", name, &type, &cals, &price)!=EOF)
{
food_stuff fs;
fs.name = name;
fs.type = type;
fs.calories = cals;
fs.price = price;
fflush(stdin);
addItem(fs);
}
}

As a commenter already has pointed out, you need to allocate memory for your variable name. Because the variable is temporary, you could just declare a local char array on the stack instead of allocationg memory on the heap:
char name[40];
Your problem is that the name field in your structure is probably also only a pointer to char. That pointer points to name for all footstuff structs you generate, which is the same for all instances, only with different contents. (What's worse: That buffer won't exist any more if you leave readFromFile, invalidating the name field for every foodstuff.)
One possible solution is to make the name field also a buffer, e.g:
typedef struct food_stuff food_stuff;
struct food_stuff {
char name[40];
int type;
int cals;
int price;
};
When you assign the read data to the struct, don't copy the pointer, but copy the contents with strcpy. (You need to include <string.h> for that):
strcpy(fs.name, name);
This solution assumes that all names are less than 39 characters long, which is not a safe assumption for real data. You should specify a width on the %s format in your call to fscanf.
Another solution is leave the struct definition as I assume it is now with char *name and to allocate memory for each new struct. You still have to copy the contents, though:
fs.name = malloc(strlen(name) + 1);
// error check omitted
strcpy(fs.name, name);
This solution requires that you free the extra memory allocated when you free the foodstuff structs.

Related

Dynamically expanding C code without using realloc

I need to put the names separated by commas from the text into struct that expands dynamically, but I am prohibited from using realloc ().I'm getting a core dumped error in this code. What is the error in this code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct movie{
double budget;
int genre;
char* name;
double score;
int year;
};
void recorder_function(struct movie *movies){
FILE*fp;
fp=fopen("Movies.txt","r");
struct movie *p;
int i,n=0;
char line[1000];
char temp_budget[50];
char temp_name[50];
char temp_genre[50];
while (!feof(fp)) {
fgets(line,1000,fp);
sscanf(line,"%50[^,],%50[^,],%50[^,]",temp_budget,temp_genre,temp_name);
//I open the fields in this section
movies=(struct movie *)calloc(n+1,sizeof(struct movie));
p=(struct movie *)calloc(n+1,sizeof(struct movie));
p[n].name=(char*)malloc(sizeof(char)*(strlen(temp_name)+1));
movies[n].name=(char*)malloc(sizeof(char)*(strlen(temp_name)+1));
for(i=0;i<n;i++)
movies[i]=p[i];
strcpy(movies[n].name,temp_name);
free(p);
p=movies;
n++;
}
for(i=0;i<n;i++)
printf("%s\n",movies[i].name);
}
int main(){
int choice;
struct movie *movies;
recorder_function(movies);
}
It is a bad idea to overwrite the pointer movie by newly allocated clean buffer.
Instead of that, you should
Allocate new buffer only for p.
Put the new element to p[n]
Put existing elements movie[0], ... , movie[n-1] to p[0], ... , p[n-1]
Free the old buffer movie
Assign the new buffer p to movie
Don't forget to initialize movie not to cause troubles at the first freeing.
Also while (!feof(fp)) is wrong and you should check if readings are successful after trying to read and before using what are read.
One more important point is that you should make sure that fopen() succeeded. Passing NULL, which fopen() returns on failure`, to other file manipulation functions may cause troubles.
Another point is that your arrays used for sscanf() outputs should have one more elements for the terminating null-character.
Yet another point is that casting results of malloc() family is considered as a bad practice.
Try this:
void recorder_function(struct movie *movies){
FILE*fp;
fp=fopen("Movies.txt","r");
if(fp==NULL){
fputs("file open error\n", stderr);
return;
}
struct movie *p;
int i,n=0;
char line[1000];
char temp_budget[51];
char temp_name[51];
char temp_genre[51];
movies=NULL;
while (fgets(line,1000,fp)) {
sscanf(line,"%50[^,],%50[^,],%50[^,]",temp_budget,temp_genre,temp_name);
//I open the fields in this section
p=calloc(n+1,sizeof(struct movie));
p[n].name=malloc(sizeof(char)*(strlen(temp_name)+1));
strcpy(p[n].name,temp_name);
for(i=0;i<n;i++){
p[i]=movies[i];
}
free(movies);
movies=p;
n++;
}
for(i=0;i<n;i++){
printf("%s\n",movies[i].name);
}
}
The next stage will be fixing the weird usage of the argument movie. Arguments in C are copies of what are passed, and modifications of arguments in callee functions won't affect what are passed in caller. Your choice is:
Remove the argument movies and convert that to a local variable.
Have recorder_function take a pointer to struct movie* (struct movie**) and have it use the pointer to modify what caller specifies. (You also have to change the statement to call the function to pass a pointer in this case)

Why do I get seg fault when using char* in my struct name but not when I use char[]? [duplicate]

This question already has an answer here:
Definitive List of Common Reasons for Segmentation Faults
(1 answer)
Closed 2 years ago.
I am just trying to understand why i get a segmentation fault when I use char *name as the member of the struct name... as apposed to char name[30] as the member, which works properly.
thankyou.
struct name
{
char *name1; // if i make this char name[30]; it works properly
};
void name_prompt(struct name *ptr)
{
printf("name: ");
scanf("%s", ptr->name1);
}
int main ()
{
struct name dylan;
struct name *ptr = &dylan;
name_prompt(ptr);
printf("%s", dylan.name1);
}
char name[30]; actually allocates 30 bytes of space within the struct for reading into. char* name just declares name as a pointer, saying that it could possibly be pointing to allocated space, but not necessarily. You never actually allocate space, so it segfaults.
On a side note, you should use %30s instead of %s for security reasons. (see here)
With a char*, you don't actually have any memory allocated to hold the data you're reading in. You didn't initialize the pointer, so it's pointing to some (semi-)random place, and writing to where it points is undefined behavior, so anything can happen.
If you want it to work with a char*, you'd need to malloc some storage for the pointer to point to (ideally freeing it when you're done), e.g.
int main ()
{
struct name dylan;
dylan.name = malloc(50); // Allocates space for up to 49 characters plus a NUL terminator; limit the scanf to match
name_prompt(&dylan);
printf("%s", dylan.name1);
free(dylan.name); // Release the memory
}
Using the array means the struct itself contains the memory wherever the struct was placed (so the struct is much larger, but doesn't rely on additional memory being allocated to be fully functional), in this case on the stack.

using memcpy to copy arrays passed as parameters

I want to copy the content of some char-arrays passed as parameters in a function to another char-arrays. So I passed these arrays as pointers (passing by reference). Then I used memcpy to copy the content of these arrays to some other arrays. But the copying-process was not too exact, although I think that I used memcpy correctly. Some characters was deleted, while some new charcters appeared. I tried then to use strcpy, so the content of these arrays was correctly copied. So I want to understand why copying process failed when using memcpy. Here is the some of my code:
struct student{
bool statusFlag;
char lastname[20];
char firstname[20];
int mNr;
};
here is the method:
struct student getData(char * lastname, char * firstname, int matNr){
struct student st;
int i;
printf("%s\n",lastname);
if(insertCounter<=size){
//get data
st.statusFlag=1;
memcpy(st.lastname,lastname,strlen(lastname));
memcpy(st.firstname,firstname,strlen(firstname));
st.mNr=matNr;
printf("%s,%s,%d\n",st.lastname,st.firstname,st.mNr);
return st;
}else if(insertCounter>size){
st.statusFlag=0;
return st;
}
When I replaced memcpy with strcpy, The copy-operation was successful:
The statement
memcpy(target,source, strlen(source))
should copy all the chars of the string. But, it will stop just short of copying the 0-byte that marks the end of the string. So what you copied won't be a string. This will be a problem if you call any string functions on the new copy (target), basicaly if you use target in any way, you will march off the end, since the end is now unmarked. Probably you will pick up some extra bytes, anything that happens to be in memory after target, worst case you program segfalts if it marches far enough without finding a 0. The function strcpy will copy the 0-byte, I usually use
snprintf(target, sizeof target, "%s", source);
Since it does not write past the end of the target buffer, and it always makes room for the 0, protecting against trouble in the next string op.

Segfault when I try to add variables to my struct

I just began starting to code in C and having a lot of difficulties with an assignment. I'm suppose to use malloc and free to create a record database using structures. The structures will act as my database. I need to be able to add and delete records. I also cant use arrays for my structures but can use arrays anywhere else in the code. The teacher gave me an idea on how to lay out the code but I don't understand how to save my inputs to add it to a record. Any help??
I have a lot of my code commented out to trouble shoot. also the the two printf statements on the bottom of main are there for troubleshooting. I can get it to print out first name but soon as I add last name, I get a seg fault. I believe I'm not allocating memory for this to happen but don't fully understand this stuff yet.. PLEASE HELP! Thanks!!!!
The problem lies in "library" variable of type "struct record" initialization or actually the lack of it:
struct record library; //this will hold info for user input
fName and lName members are uninitialized pointers to char. Allocate memory for your buffers and initialize those pointers to point to those buffers. Uninitialized pointers simply point to "some" memory location. When you put data into that location anything can happen! Alternatively provide fixed size buffers in place of those pointers like:
struct record {
char fName[100];
char lName[100];
};
That should work as the first step. Next is to use the malloc/free as your assignment says. Revert struct record back to the original format and use malloc to reserve memory for your buffers before passing them to any function or otherwise using them; like so
#define BUFSIZE (100)
library.fName = malloc(BUFSIZE);
library.lName = malloc(BUFSIZE);
After memory reservation you may use them but don't pass more than BUFSIZE number of characters to those buffers.
After you are done with your buffers free the allocated memory:
free(library.fName);
free(library.lName);
After freeing the buffers you may not use them anymore.
Also don't use gets(). It doesn't provide any protection for buffer overflows as the maximum buffer size is not passed as a parameter to gets(). It has been deprecated and will be removed from the forthcoming standard C1X as unsafe.
Because you are reading data into uninitialized pointers:
printf ("Please enter your first name:\n");
gets(library.fName);
printf ("Please enter your last name:\n");
gets(library.lName);
Allocate memory using malloc and use them and free() them once you are done. If you don't need pointers, you can use arrays in your struct.
Please don't gets() as it can't prevent buffer overflow. Use fgets() instead.
int main() should be int main(void) or int main(int argc, char *argv[]) or its equivalent.
None of your struct members have memory allocated to them. For ease, first define them as
char fName[10];
char lName[10];
etc,
Once you are comfortable with this, then try memory allocation. (IOW, one concept at a time)
The problem you have having is that you are not actually allocating any memory to store the input. Let's start with your struct:
struct record{
char * fName;
char * lName;
};
In memory this struct is just two char pointers. The struct itself is 8 bytes long. The pointers aren't initialized to anything, so they have random values. When you use them as pointers, you will point to a random location in memory.
If you want to actually store the first and last names in your struct, then you could create the struct like this:
static const int MaxNameLength = 255;
struct record{
char fName[MaxNameLength + 1];
char lName[MaxNameLength + 1];
};
Alternately you could use the struct the way that you wrote it, but allocate memory for the buffers and update the pointers. If you did that you would need to do this:
static const int MaxNameLength = 255;
struct Record library;
library.fName = (char *)malloc(MaxNameLength + 1);
library.lName = (char *)malloc(MaxNameLength + 1);
Both these methods are valid, but the advantage to the first method is that you would not need to clean up memory yourself. When the struct goes out of scope all the memory is freed. If you malloc the memory yourself, then you also need to free it.
struct record{
char * fName;
char * lName;
//char * sAddress;
//char * city;
//char * state;
//int * zip;
};
In your structure you are using char * fname
but you input method was not correct you have to do malloc for that
But for a newbie in C
keep fname and lname as char array like
struct record{
char fName[100];
char lName[100];
//char * sAddress;
//char * city;
//char * state;
//int * zip;
};
Now your above code works fine ..
fName and lName are pointers, in general you have to allocate memory to each pointers and free memory for each pointer too. If you read or write on a pointer which is unassigned memory segmentation fault will occur,
You can create an array like name[20] and use gets function. Allocate memory to lName and fName like malloc(strlen(name)). Later on free in the end. Try to malloc and free in main function as it can create problem (you will learn later on pass by value and pass by refernce issues)

Getting error while initializing structure variable?

I am confused about why I am getting an error while initializing a structure variable. I have found a few related threads on Stack Overflow, but they did not solve my problem. Can anyone explain what is causing the problem?
//I have used Dev-C++ compiler
//Getting an error 'b1' undeclared
struct book
{
char name ;
float price ;
int pages ;
};
struct book b1;
int main()
{
/* First i have tried following way to initialize the structure variable,
but compiler throws the error
b1 = {"John", 12.00, 18};
*/
//I have tried to initialize individually ....but still getting error...?
b1.name = "John";
b1.price = 12.3;
b1.pages = 23;
printf ( "\n%s %f %d", b1.name, b1.price, b1.pages );
system("pause");
return 0;
}
Problems
only one byte memory available for name field. use like char name[100]
use strcpy() instead of b1.name = "John";
You clearly want a string variable in your struct, but you declared it as char name; (a single character).
Instead, use a char pointer (const char *name), or a char array (char name[100]). In the latter case, you will have to use strcpy(b1.name, "John").
The problem is that you have declared name as a char. That means name will hold only a single char, not an entire string.
You can statically allocate name as an array of char:
char name [25] // or whatever length you think is appropriate
// remember to leave room for the NUL character
Then you will need to use strcpy() to copy the actual name into the structure.
Alternatively, you can declare name as a pointer to char:
char* name;
In this case, you can set the pointer to a string literal:
name = "John";
But in most real life situations, this is not an option, as you will be reading the name in from a file or standard input. So you will need to read it into a buffer, set the pointer to dynamically allocated memory on the heap (the string length of the buffer + 1 for the NUL), and then use strcpy().
You have to do some tweaks to your code in order to make it work.
char name; // only one byte is allocated.
Define char array to store strings in C.
char name[20]; //stores 20 characters
char *name; //Pointer variable. string size can vary at runtime.
Once you have created a object for your structure than you can feed data only using that object.
(i.e) object.element=something;
b1 = {"John", 12.00, 18}; // Not possible
The above initialization is possible only while defining objects.
struct book b1={"John", 12.00, 18}; //Possible
If char *name is defined inside struct, you can do the following.
struct book b1;
b1.name="John"; // Possible
b1.price=12.00; // Possible
b1.pages=18; // Possible
If you use char array char name[20] then you can do the following.
struct book b1;
strcpy(b1.name,"John"); // Possible
b1.price=12.00; // Possible
b1.pages=18; // Possible

Resources