still really new to C but starting to get the hang of it....
My program is supposed to create/write a file and store information from an array of structures. That part is fine. What im having trouble with is reading from that file back into an empty array of structures....
here's my structs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
struct Video {
char name[1024]; //name
int ranking; // Number of viewer hits
char url[1024]; // YouTube URL
};
struct Video Collection[MAX];
here's my load method which reads from my file back into my array of structures:
void load()
{
FILE *fileName;
fileName = fopen("ranking.dbm", "rb");
if (fileName != NULL){
fread (Collection,1,1,fileName);
}
else {
printf("ERROR");
}
}
also here is my write method:
void save()
{
FILE * pFile;
pFile = fopen ( "Ranking.dbm" , "wb" );
fwrite (Collection, 1 , sizeof(Collection), pFile );
fclose (pFile);
}
however when i print out my array collection after loading.... its empty... even though i can see my file in the project folder and open it and verify that the data is in there....
am i correct in thinking that i dont need a buffer since i don't need to do any processing on it before using it?
also since i've already statically allocated space for memory.... am i correct in thinking that i can just read directly into the array?
here is my print code:
void printall()
{
int i;
printf("\nCollections: \n");
for(i = 0; i < tail; i++)
{
printf("\nVideo Name: %s", Collection[i].name);
printf("\nRanking (Hits): %d", Collection[i].ranking);
printf("\nURL: %s", Collection[i].url);
printf("\n");
}
}
fread is in fact designed to read arrays of structures from a file, but you have to use it correctly.
fread's four parameters are as follows:
void * ptr, size_t size, size_t count, FILE * stream
The first parameter is where to put the data (in your case, Collection). The second parameter is the size of each array element: in your case, you want to put sizeof(struct Video). The third parameter is the number of elements you want to read, in your case, MAX. The fourth parameter is the file to read from.
If you want to read into an array like struct Video Collection[MAX], you would then use fread(Collection, sizeof(struct Video), MAX, file). fread will return the total number of elements read, which will be ≤ MAX.
I'm seeing a few issues here.. first how you read the file:
fread (Collection,1,1,fileName);
This will read into collection 1 byte from fileName into Collection
You should check the return status of fread(), when it's successful it tells you the total number of bytes to be read. (parameter 2 * parameter 3, or 1*1 in your case).
When I modify your read code like this:
fread(Collection, sizeof(struct Video), 1, fileName);
It does successfully read from the file... however you have a different problem now. Let's say your file contained this:
something 5 http://something.com
nothing 3 http://nothing.com
So (I think) that's the format for your file, a name (ASCII), a ranking (int), and URL (ASCII). Now let's say your main() function looked like this:
int main ()
{
load();
printall();
return 0;
}
What you'd get back on stdout would be something like:
Collections:
Video Name: something 6 http://something.com
nothing 3 http://nothing.com
Ranking (Hits): 0
URL:
The reason is because you declared your array with static (and very large) elements. The fread() will try to read in the sizeof(struct Video) which is 1024+4+1024 bytes, so unless every one of your lines is the exact size (1024 chars for name and url) then you're going to get what looks like messed up or empty data.
I would suggest reading until you hit a space instead and storing each value in the correct element instead of trying to read out the full file into an array.
EDIT:
If you want to populate your array like:
fread(myarray, sizeofstruct, numberofstructs, file);
You have to guarantee the data length. In your example you'd have to say "name is however many characters, + blank spaces = 1024" and same for URL. That seems to be a horrible space waster. The better bet is to populate your array one element at a time:
for(0 to last_element){
set myarray.name = data until first space
set myarray.ranking = (int)data until second space
set myarray.url = data until newline
}
You can use fscanf() to read until a whitespace.
Frankly if you're going to populate one element at a time I'd just use character pointers for name and url and dynamically assign memory so you don't have huge wasted arrays.
First I have to assume you meant struct Video Collection[MAX];else your upper part is invalid C.
Second: you are reading 1 byte into Collection.
Try
fread(Collection, sizeof(struct Video), MAX, fileName);
This will read up to MAX times chunks of sizeof(struct Video)bytes into Collection.
Related
i am trying to create a record keeping random access file in C. As you know, in random access file, all the records are given a fixed standard byte length. so that they can be accessed randomly when needed using fseek() and fread() functions. Here i have kept that length as size of whole structure, which is 90 bytes. i have multiple character arrays in structure. when i get input from user in those arrays of characters using structure object, and pass that object to the fwrite function and i give size as size of structure, the character array data is written to the file. but because the text from user is mostly is less than 30 chracters mostly( max size of array), the fwrite function writes the string from user in file but also writes garbage values in file for those indexes which were not used in array. if i use fseek and fread() functions, the program reads data fine. but i want my file to be garbage values free and human readable. How can i do that?
`#include <stdio.h>
#define size 30
struct Record{
char account[size];
char name[size];
char address[size];
};
int main()
{
FILE *ptr = NULL;
ptr = fopen("testfile.txt", "w");
if (ptr == NULL)
{
printf("Could not open file.");
}
else
{
struct Record client;
char account[30];
char name[30];
char address[30];
printf("Enter account number: ");
gets(client.account);
printf("Enter name: ");
gets(client.name);
printf("Enter address: ");
gets(client.address);
fwrite(&client, sizeof(struct Record),1,ptr);
fclose(ptr);
ptr = fopen("testfile.txt", "r");
char buffer[size];
fseek(ptr,0,SEEK_SET);
fread(buffer,30,1,ptr);
puts(buffer);
fclose(ptr);
}
puts("Done!");
return 0;
}`
The data in file i am getting is of follwing form (input: 1 jack new york):
1 ((± 0(± /Œ¬¨þa òpv ± jack ‚Ž ((± 0(± 0(± ¤þnew york lþa à# €# 4(±
I think the problem above is due to the larger size given than length of strings. i also tried giving size as length of string. In that case, the garbage values were not printed. but in that case i will lose my principle of keeping each record of same length to have random access property in file. So how can i write my string data to file without writing garbage values and yet keep the length of each record same as standard lentgh we have decided.
I just recently found the solution to my problem. It was to place space characters ' ' after terminating character in the array. for example, if I have an array of size 30 and I have given it a string of only 10 characters, with the terminating character at the 11th position, I can store space in the remaining ones. so that when I write a whole string with size 30 in the file, the space characters are written and we do not get garbage values appearing in our file. instead, we will have our strings readable in the file.
I used this function for this purpose:
void spaces(char array[],int size)
{
int length = strlen(array);
for (int i = length + 1; i < size; i++)
{
array[i] = ' ';
}
}
I have read a lot of questions on this, and using them I have altered my code and have created code which I thought would work.
I think it's my understanding of C, which is failing me here as I can't see where I'm going wrong.
I get no compilation errors, but when I run i receive 'FileReader.exe has stopped working' from the command prompt.
My code is :
void storeFile(){
int i = 0;
char allWords [45440][25];
FILE *fp = fopen("fileToOpen.txt", "r");
while (i <= 45440){
char buffer[25];
fgets(buffer, 25, fp);
printf("The word read into buffer is : %s",buffer);
strcpy(allWords[i], buffer);
printf("The word in allWords[%d] is : %s", i, allWords[i]);
//allWords[i][strlen(allWords[i])-1] = '\0';
i = i + 1;
}
fclose(fp);
}
There are 45440 lines in the file, and no words longer than 25 char's in length. I'm trying to read each word into a char array named buffer, then store that buffer in an array of char arrays named allWords.
I am trying to get this part working, before I refactor to return the array to the main method (which I feel won't be a fun experience).
You are trying to allocate more than a megabyte (45440*25) worth of data in automatic storage. On many architectures this results in stack overflow before your file-reading code even gets to run.
You can work around this problem by allocating allWords statically, like this
static char allWords [45440][25];
or dynamically, like this:
char (*allWords)[25] = malloc(45440 * sizeof(*allWords));
Note that using buffer in the call to fgets is not required, because allWords[i] can be used instead, without strcpy:
fgets(allWords[i], sizeof(*allWords)-1, fp);
Also note that an assumption about file size is unnecessary: you can continue calling fgets until it returns NULL; this indicates that the end of the file has been reached, so you can exit the loop using break.
Can someone please help explain the difference in C and how my file fails to merge, and appends instead? The background is I am on an online computer science class this summer which uses C language, all we are given is read the entire texbook (732 pages), and do 20 projects over the course of 8 weeks, with no actual instruction, lecture, slides, or explanations. Please explain it so I can learn as I need to actually understand these terms to be better and progress in my Electrical Engineering program. I have contacted my professor for help but the answers are always short and uninformative, and you guys have provided so much more quality feedback to date. Also I do get that he is right and it was appended and not merged, but any feedback how i could of rectified this will help as well. Thank you again!
#include <stdio.h>
#include <stdlib.h>
FILE *inptr1, *inptr2, *outptr;
int main()
{
char c;
char file1[30], file2[30], file3[30];
printf("Enter the first files name\n");
gets(file1);
printf("Enter the second files name\n");
gets(file2);
printf("Enter the file name that will store the data from the other two files\n");
gets(file3);
inptr1 = fopen("C:\\Users\\Eric\\Desktop\\file1.txt","r");
inptr2 = fopen("C:\\Users\\Eric\\Desktop\\file2.txt","r");
if( inptr1 == NULL || inptr2 == NULL )
{
perror("Error ");
printf("Press any key to exit!\n");
exit(1);
}
outptr = fopen("C:\\Users\\Eric\\Desktop\\file3.txt","w");
if( outptr == NULL )
{
perror("Error ");
printf("Press any key to exit!\n");
exit(1);
}
while( ( c = fgetc(inptr1) ) != EOF )
fputc(c,outptr);
while( ( c = fgetc(inptr2) ) != EOF )
fputc(c,outptr);
printf("The two files were sucessfully merged into %s \n",file3);
fclose(inptr1);
fclose(inptr2);
fclose(outptr);
return 0;
}
Page 611 #5 Write a complete C program. Use the two files provided. Your program should not assume that you know which file is shorter.
5) Write a function to merge two sorted files of names and write the names to a
new file.
Was the only direction I was given as far as to what the program was supposed to do.
and this was the feedback i received, "Did you look at the resulting file?The girls names are all at the bottom. You were to merge the files,not append the files."
Thank you again in advance for your valuable feedback as it has taught me so much to date.
You're going to need to look at the contents of each file and write them to the third file in sorted order. That seems to be what the assignment is asking you to do. What you're doing currently is dumping the contents of file1.txt into file3.txt followed by the contents of file2.txt. You want to end up with a sorted list containing the contents of both files.
There are many ways to accomplish your requirements. This is just one that jumps out:
Steps to perform:
1 Open two existing files (fopen(fp, "r");), and one new file (fopen(fp, "w");)
2 write all lines of first file, then the second file to the third file. (fopen(), fgets(), fputs(), fclose(), etc.)
3 Read third file into an array of strings, keeping a count of the total number of strings read. close file.
4 Sort array of strings. (qsort())
5 Open third file, Write sorted array of strings into that file.
6 Close all files, free all memory.
Note, using this method, it does not matter if the two original files are sorted, or not, (Assignment says they are, but does not matter). The qsort routine will completely sort the string array either way.
qsort()
Most of the functions referenced are straight forward to use. qsort() is a little weird.
Here is an example showing how to set up qsort() for use sorting an array of strings:
For an array of strings: strings with the number of strings being say: cnt then:
qsort(strings, cnt, sizeof(char*), sortstring);
//With the function sortstring defined as:
static int sortstring( const void *str1, const void *str2 )
{
const char *rec1 = *(const char**)str1;
const char *rec2 = *(const char**)str2;
int val = strcmp(rec1, rec2);
return val;
}
string arrays
Creating an array of strings can also be challenging. Again, there are several ways to do this, here are two:
If you know the dimensions of each line, and the total number of lines in both files, then you can do it like this:
char strArray[numLines][longestLine];
If you don't, then you have to determine that at run-time by getting a count of the total number of lines, say when you are reading them from each file. And you will also need the length of the longest line found in both files, say by using strlen() on each one at some point as it is read or written. Once you have that information, you can create your string array like this:
char **strings=0;
Then, before you need it, create memory for it:
char **allocMemoryStr(char **strings, int numStrings, int maxLen)
{
int i;
strings = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
strings[i] = calloc(sizeof(char)*maxLen + 1, sizeof(char));
}
return strings;
}
Finally, when you are finished using dynamically allocated memory, you must always free it:
void freeMemoryStr(char **strings, int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(strings[i]) free(strings[i]);
free(strings);
}
I am completely new to C and need help with this badly.
Im reading a file with fopen(), then obtaining the contents of it using fgetc(). What I want to know is how I can access the line fgetc() returns so if I can put the 4th - 8th characters into a char array. Below is an example I found online but am having a hard time parsing the data returns, I still don't have a firm understanding of C and don't get how an int can be used to store a line of characters.
FILE *fr;
fr = fopen("elapsed.txt", "r");
int n = fgetc(fr);
while(n!= EOF){
printf("%c", n);
n = fgetc(fr);
} printf("\n");
Here
1 first open the file
2 get size of file
3 allocated size to character pointer
4 and read data from file
FILE *fr;
char *message;
fr = fopen("elapsed.txt", "r");
/*create variable of stat*/
struct stat stp = { 0 };
/*These functions return information about a file. No permissions are required on the file itself*/
stat("elapsed.txt", &stp);
/*determine the size of data which is in file*/
int filesize = stp.st_size;
/*allocates the address to the message pointer and allocates memory*/
message = (char *) malloc(sizeof(char) * filesize);
if (fread(message, 1, filesize - 1, fr) == -1) {
printf("\nerror in reading\n");
/**close the read file*/
fclose(fr);
/*free input string*/
free(message);
}
printf("\n\tEntered Message for Encode is = %s", message);
PS Dont Forget to Add #include <sys/stat.h>.
You're not retrieving a line with fgetc. You are retrieving one character at a time from the file. That sample keeps retrieving characters until the EOF character is encountred (end of file). Look at this description of fgetc.
http://www.cplusplus.com/reference/clibrary/cstdio/fgetc/
On each iteration of the while loop, fgetc will retrieve a single character and place it into the variable "n". Something that can help you with "characters" in C is to just think of it as one byte, instead of an actual character. What you're not understanding here is that an int is 4 bytes and the character is 1 byte, but both can store the same bit pattern for the same ASCII character. The only different is the size of the variable internally.
The sample you have above shows a printf with "%c", which means to take the value in "n" and treat it like an ASCII character.
http://www.cplusplus.com/reference/clibrary/cstdio/printf/
You can use a counter in the while loop to keep track of your position to find the 4th and 8th value from the file. You should also think about what happens if the input file is smaller than your maximum size.
Hope that helps.
Ok look at it as box sizes I could have a 30cm x 30cm box that can hold 1 foam letter that I have. Now the function I am calling a function that 'could' return a 60cm x 60cm letter but it 99% likely to return a 30cm x 30cm letter because I know what its reading - I know if I give it a 60cm x 60cm box the result will always fit without surprises.
But if I am sure that the result will always be a 30cm x 30cm box then I know I can convert the result of a function that returns aa 60cm x 60cm box without losing anything
How to read the data from a file to a structure?
I have a structure like
struct data
{
char name[20];
int age;
};
In file student_info.txt I have
ravi 12 raghu 14 datta 13 sujay 10 rajesh 13
and so on with many other names with ages. How can I read this from file to the structure data?
Reading this name and age should be a loop i.e for the first time I will read 'ravi' and '12', then I should pack this data in the structure and will pass the structure to a function as soon as the structure is set. It should come back to the file and read 'raghu' and '14' again pack the structure with this data, and this should be in a loop till I read all the data from the file
Can anyone please tell how to implement the logic?
The approach is:
Create an instance of an array of your struct, a file pointer for file access, and a counter variable
Open the file stream using the file pointer - check that it has been successfully opened. The file pointer will point to NULL if fopen() has failed
Read the data into the struct array using a loop. fscanf() returns the number of successful 'matches' with its format string - here it will be 2 (use this for the loop condition)
Close the file
An example of the code:
#include <stdio.h>
#define FILENAME "student_info.txt"
#define MAX_NO_RECORDS 50
struct data
{
char name[20];
int age;
};
int main(void)
{
/* Declare an array of structs to hold information */
struct data StudentInfo[MAX_NO_RECORDS];
/* Declare a file pointer to access file */
FILE *s_info;
int student_no = 0; /* holds no. of student records loaded */
/* open the file for reading */
s_info = fopen(FILENAME, "r");
/* Check if an error has occured - exit if so */
if(s_info == NULL)
{
printf("File %s could not be found or opened - Exiting...\n", FILENAME);
return -1;
}
printf("Loading data...\n");
while(fscanf(s_info, "%19s %i", StudentInfo[student_no].name, &StudentInfo[student_no].age) == 2)
{
/* refer to records with index no. (0 to (1 - no. of records))
individual members of structure can be accessed with . operator */
printf("%i\t%-19s %3i\n", student_no, StudentInfo[student_no].name, StudentInfo[student_no].age);
student_no++;
}
/* after the loop, student_no holds no of records */
printf("Total no. of records = %i\n", student_no);
/* Close the file stream after you've finished with it */
fclose(s_info);
return 0;
}
You just need to read data from this file and split that string based on some criteria. as your file is not properly formatted it would be difficult for you to parse data.
In your current scenario your file contain only first name and a digit you can easily parse this by detecting a Space Character in your string. but this could lead a problem if any of your name contains a space.
First of all separate each pair of word by some character such as : or ; or a tab or line break.
then between each separated string split it by space and then read all content of file in a char array then from that array try to find that special character which indicates one record.
Separate each record in a different char array then for each generated array again and then split it based on space char and load in your struct
This is just for explanation, original implementation may be different,
Student std = {first string, second integer};
Hope that document solves your problem http://www.softwareprojects.com/resources//t-1636goto.html