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] = ' ';
}
}
Related
Example file:
School Name (with spaces)
FirstNameofStudent StudentID
School Name2 (with spaces)
FirstNameofStudent2 StudentID2
School Name3 (with spaces)
FirstNameofStudent3 StudentID3
I cant seem to figure out what to do after using fgets for the first line.
If by itself, I can easily get school name using fgets
and the second line by itself using fscanf then converting the studentID to int using atoi.
But how do I combine both fgets and fscanf?
The information scanned would be placed into an array.
Before I go onto the solution, I want to point out that an array can only have a single type. You cannot store integers in an array of characters.
Meaning if you would like all of this information to go in a single 2D array, you'd need to store the ID as a string. Then if you need it as an integer, you'd need to use atoi on it once you retrieve it.
Now for combining the two, you'd need a while loop with fgets in the condition in order to retrieve the first line. Something like this:
while(fgets(schoolname, 255, fp) != 0){ ... }
This would keep on retrieving lines until it fails, or it reaches EOF. However, you wanted to use fscanf for the second line, and for that, you'd need a line like this:
fscanf(fp, "%s %s\n", name, id);
This means, from the current point, there are two strings seperated by a space, and a newline. Store the two strings in name and id, and gobble the newline.
Gobbling the newline is key, as if you don't do it, the next time fgets runs, it would only find a single newline on the line.
As for storing the elements in an array, you'd need a 2D array of strings. For that, you can either do it fixed, or dynamic. For fixed, it's pretty easy, just have a line like char students[3][3][80] and simply store stuff in there, but for dynamic, you'd need to use memory allocation, pointers, etc, with a variable liks char ***students
Here's the code I used to solve your problem, though I suggest trying to do this on your own as well, to get the hang of it:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
FILE *fp = fopen("ex.txt", "r");
if(fp == 0) exit(-1);
char ***students;
// Used to check how many students there are
int studentno = 0;
// Init students array
// So far it means 1 ROW, with 3 COLUMNS, each of 80 CHARACTERS
students = calloc(studentno+1, 3 * 80);
// Temporary variables for storage
char schoolname[80];
char name[20];
char id[10];
int i = 0;
while(fgets(schoolname, 255, fp) != 0){
studentno++;
// Retrieve name and id from second line
fscanf(fp, "%s %s\n", name, id);
// Cut off newline left from fgets
schoolname[strlen(schoolname)-2] = 0;
// Allocate memory for new members of array
students[i] = malloc(3 * 80);
students[i][0] = malloc(80);
students[i][1] = malloc(80);
students[i][2] = malloc(80);
// Copy strings received into array
strcpy(students[i][0], schoolname);
strcpy(students[i][1], name);
strcpy(students[i][2], id);
// Resize students array for additional students
students = realloc(students, (size_t) (studentno+1) * 3*80);
i++;
}
// Check students are stored correctly
for(int i = 0; i < studentno-1; i++){
printf("%s - %s - %s\n", students[i][0], students[i][1], students[i][2]);
}
}
I'm getting some issues with reading the content of my array. I'm not sure if I'm storing it correctly as my result for every line is '1304056712'.
#include <stdio.h>
#include <stdlib.h>
#define INPUT "Input1.dat"
int main(int argc, char **argv) {
int data_index, char_index;
int file_data[1000];
FILE *file;
int line[5];
file = fopen(INPUT, "r");
if(file) {
data_index = 0;
while(fgets(line, sizeof line, file) != NULL) {
//printf("%s", line); ////// the line seems to be ok here
file_data[data_index++] = line;
}
fclose(file);
}
int j;
for(j = 0; j < data_index; j++) {
printf("%i\n", file_data[j]); // when i display data here, i get '1304056712'
}
return 0;
}
I think you need to say something like
file_data[data_index++] = atoi(line);
From your results I assume the file is a plain-text file.
You cannot simply read the line from file (a string, an array of characters) into an array of integers, this will not work. When using pointers (as you do by passing line to fgets()) to write data, there will be no conversion done. Instead, you should read the line into an array of chars and then convert it to integers using either sscanf(), atoi() or some other function of your choice.
fgets reads newline terminated strings. If you're reading binary data, you need fread. If you're reading text, you should declare line as an array of char big enough for the longest line in the file.
Because file_data is an array of char, file_data[data_index] is a single character. It is being assigned a pointer (the base address of int line[5] buffer). If reading binary data, file_data should be an array of integers. If reading strings, it should be an array of string, ie char pointers, like char * file_data[1000]
you also need to initialize data_index=0 outside the if (file) ... block, because the output loop needs it to be set even if the file failed to open. And when looping and storing input, the loop should test that it's not reached the size of the array being stored into.
code doesnt accept values from file since when i print some garbage pops up
the file is a textfile with a letter representing a status, and theres a number. there are 5 sets of these , each on new line the letter and the number is seperated with a space, i need to get the numbers in one array
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char status;
int number;
} information;
int main() {
int array[5] = {0};
int i;
FILE *pointer = fopen("transaction22.txt", "r");
information information1;
for (i = 0; i < 5; i++) {
fread(&information1, sizeof(information1), 1, pointer);
array[i] = information1.number;
printf("%d", information1.number);
}
return 0;
}
You can use fscanf instead of fread as:
fscanf(pointer, "%s %d", info1.status, &info1.number);
where status will be defined as char status[2]; inside struct information.
fread is used for reading raw bytes (blocks of data) from a file.
Now, you are using a text file and trying to read sizeof(info) amount of data which is 5 bytes of data (assuming 32-bit int), therefore what you get after first fread is:
info1.status (1 byte) info1.number (4 bytes)
Byte 1 SPACE + number + NEWLINE + [One more byte]
read by fread (next four bytes read by fread)
Thus info1.number is storing a garbage value.
Also the successive fread call starts reading after the data read by previous fread.
Better to use a character array like c[5]. and replace this is with struct. variable in fread ..like in for loop
fread(c,sizeof(c),1,pointer)
than use
print("%s\n",c);
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.
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