i have a file needed to be read by code. The file is shown as below. The very first line of the file contains a single integer, indicating the number of journal entries in the file. I need to write a C program to read a file and store the contents in a dynamically-allocated array of structs.
4
12/04/2010
Interview went well I think, though was told to wear shoes.
18/04/2010
Doc advised me to concentrate on something... I forget.
03/05/2010
Was asked today if I was an art exhibit.
19/05/2010
Apparently mudcakes not made of mud, or angry wasps.
I was able to strtok() the day, month and year to store in my struct, however I am stuck in saving the strings to my structs. Here is my code for strtok(),
FILE* file=fopen("struct.txt","r");
if (file==NULL){
perror("Error opening file\n.");}
else {
fscanf(file,"%d",&size);
res=(Diary*)malloc(size*sizeof(Diary));
fscanf(file,"%*[^\n]");
while(fgets(day,1024,file)!= NULL){
oken=strtok(day,"/");
h[i]=atoi(oken); */h[i] is my day
oken=strtok(NULL,"/");
fre[i]=atoi(oken); */fre[i] is the month
oken=strtok(NULL,"/");
re[i]=atoi(oken); */ re[i] is the year
okena=strtok(day,"\n");
strcpy(rese[i],okena); */i had declared rese as char rese[1024]
printf("%s",okena);
i++;
}
the program is not working with that strcpy(), when i run it, it keep crashing. However if i remove the strcpy(), it will print as follow:
12
Interview went well I think, though was told to wear shoes.
18
Doc advised me to concentrate on something... I forget.
03
Was asked today if I was an art exhibit.
19
Apparently mudcakes not made of mud, or angry wasps.
which this is not the strings i want to store in my struct as well. I am stuck in how to store the strings into a struct. My struct is
typedef struct journal{
int day;
int month;
int year;
char entry[1024];
} Diary;
Any good souls could tell me what is wrong?
the following proposed code:
and now the proposed code:
Your problem presents the classic problem of "How do I read and allocate for X number of something when I don't know how many beforehand?" This is actually a simpler variant of the question, because you can read the
X
number as the first line from your data file.(which simplifies the problem to a single allocation of X structs after reading the first line - otherwise you would need to keep track of the current number of structs allocated and
realloc
as required)To begin, I would recommend against creating
char entry[1024];
within your struct for two reasons - first, the automatic storage forentry
is created on the stack and a large diary could easily StackOverflow... Second, it's just wasteful. If the goal is dynamic allocation, then allocate only the storage necessary for eachentry
. You can declare a single buffer of1024
chars to use as a read buffer, but then allocate onlystrlen (buf) + 1
char to hold the entry (after trimming the included'\n'
from the entry).The remainder of your problem, is the basis for any reliable code, is simply to validate each read, each parse, and each allocation so you insure you are processing valid data and have valid storage throughout your code. This applies to every pieces of code you write, not just this problem.
Putting those pieces together, and providing further details inline in the comments below, you could do something like the following:
(note: you can further simplify the code by using POSIX
getline()
for your read instead of a fixedbuf
and you can simplify the allocation and copy of each entry into your struct usingstrdup()
, but neither are guaranteed available to all compilers -- use them if your compiler supports them and portability everywhere isn't a concern. Also note the GNU gcc uses%zu
as the format specifier forsize_t
. If you are on windoze, change each to%lu
)Example Input File
Example Use/Output
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux
valgrind
is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.(note: the storage required for all diary entries (the entire diary) is only
309-bytes
that is less than1/10th
the storage required declaringchar entry[1024];
)Always confirm that you have freed all memory you have allocated and that there are no memory errors.
MS Windows
Since you seem to be having problems on windows, the following is the code above, with nothing but
%lu
substituted for%zu
(as windows treats%zu
as a literal), compiled on Win7 with an older version of VS compiler:Compile
(note: I put my .obj files in a subdirectory
./obj
and my binary executables in./bin
to keep my source directory clean. That is the purpose of/Foobj/diary
and/Febin/diary
above)Example Use/Output
You must insure you change, each and every
%zu
to%lu
or you cannot expect proper output. You say you have changed all toint
, but the snippet you posted in the comments below contains%zu
-- this will not work on windows.Look things over and let me know if you have further questions.