Reading data from file to struct using fread - c

I'm writing a piece of code and a part of it is reading "records" from file to n-length array, n given as an argument. Records in file have constant length(in this case 1024) and contain only numerics, spaces and lower letters. Each record is terminated with \n. I'm using following structure to keep one record:
typedef struct{
char rec[1024];
} record;
And Code for extracting n of them and storing in n-length array of records is written this way:
record * recs=malloc(n*sizeof(record));
size_t read=fread(recs,sizeof(record),(size_t)n,f);
When I checked output of this operations it turns out that first element of array recs contains all of the records, second all but first and so on instead of keeping one at each element of array. I'm kind of lost, because i thought that it should store each record in different element of array.
As suggested, I'm also providing code for opening a file and printing elements of array:
if((f=fopen(argv[2],"r"))==NULL){
perror("error opening file\n");
exit(1);
}
for(int i=0;i<(int)read;i++){
printf("record number %d\n %s\n",i,recs[i].rec);
}

The problem is that your records rec isn't a zero terminated string.
So printing using %s shows all records because the printing will just continue until it sees a '\0'.
So either make sure to add a zero-termination in each rec or use another way of printing than %s.
BTW: If there isn't any zero-termination inside recs you actually have undefined behavior.
This little program mimics the problem:
#include <stdio.h>
struct r {
char c[1];
};
int main(void) {
int i;
struct r recs[4] = {{'a'}, {'b'}, {'c'}, {'\0'}};
// ^^^^^
// Just to stop printing here
for (i=0; i<3; i++)
{
printf("%d %s\n", i, recs[i].c);
}
return 0;
}
Output:
0 abc
1 bc
2 c

Related

How to avoid garbage values while writing to a file

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] = ' ';
}
}

Storing String Inside a String?

My problem is when I try to save the string (series[0]) Inside (c[0])
and I display it, it always ignore the last digit.
For Example the value of (series[0]) = "1-620"
So I save this value inside (c[0])
and ask the program to display (c[0]), it displays "1-62" and ignores the last digit which is "0". How can I solve this?
This is my code:
#include <stdio.h>
int main(void)
{
int price[20],i=0,comic,j=0;
char name,id,book[20],els[20],*series[20],*c[20];
FILE *rent= fopen("read.txt","r");
while(!feof(rent))
{
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
i++;
}
c[0]=series[0];
printf("\n%s",&c[0]);
return 0;
}
The use of fscanf and printf is wrong :
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
Should be:
fscanf(rent,"%c%c%s%d",&book[i],&els[i],series[i],&price[i]);
You have used the reference operator on a char pointer when scanf expecting a char pointer, also you read a string to book and else instead of one character.
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
Should be:
printf("1.%c %c %s %d",book[i],els[i],series[i],price[i]);
And:
printf("\n%s",&c[0]);
Should be:
printf("\n%s",c[0]);
c is an array of char * so c[i] can point to a string and that is what you want to send to printf function.
*Keep in mind that you have to allocate (using malloc) a place in memory for all the strings you read before sending them to scanf:
e.g:
c[0] = (char*)malloc(sizeof(char)*lengthOfString+1);
and only after this you can read characters in to it.
or you can use a fixed size double character array:
c[10][20];
Now c is an array of 20 strings that can be up to 9 characters long.
Amongst other problems, at the end you have:
printf("\n%s",&c[0]);
There are multiple problems there. The serious one is that c[0] is a char *, so you're passing the address of a char * — a char ** — to printf() but the %s format expects a char *. The minor problem is that you should terminate lines of output with newline.
In general, you have a mess with your memory allocation. You haven't allocated space for char *series[20] pointers to point at, so you get undefined behaviour when you use it.
You need to make sure you've allocated enough space to store the data, and it is fairly clear that you have not done that. One minor difficulty is working out what the data looks like, but it seems to be a series of lines each with 3 words and 1 number. This code does that job a bit more reliably:
#include <stdio.h>
int main(void)
{
int price[20];
int i;
char book[20][32];
char els[20][32];
char series[20][20];
const char filename[] = "read.txt";
FILE *rent = fopen(filename, "r");
if (rent == 0)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", filename);
return 1;
}
for (i = 0; i < 20; i++)
{
if (fscanf(rent, "%31s%31s%19s%d", book[i], els[i], series[i], &price[i]) != 4)
break;
printf("%d. %s %s %s %d\n", i, book[i], els[i], series[i], price[i]);
}
printf("%d titles read\n", i);
fclose(rent);
return 0;
}
There are endless ways this could be tweaked, but as written, it ensures no overflow of the buffers (by the counting loop and input conversion specifications including the length), detects when there is an I/O problem or EOF, and prints data with newlines at the end of the line. It checks and reports if it fails to open the file (including the name of the file — very important when the name isn't hard-coded and a good idea even when it is), and closes the file before exiting.
Since you didn't provide any data, I created some random data:
Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
The output from the code above on that data is:
0. Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
1. Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
2. Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
3. Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
4. Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
5. Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
6. Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
7. Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
8. Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
9. Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
10 titles read

read csv file into 2-d array in c

I'm not familiar with C at all. I just need to input my data into an already well-developed model in C, put the data in arrays, get my output and put that output back into my program in Python. My data is in a CSV file and I'm just trying to put it in a 2-D array to run through some functions. When I run the following code to make sure I created my array, I get a random single value in the output that does not match the original data at all. Sometimes it prints 0.00000. I'm trying to view the entire array to make sure it's ready to be input.
Also, this is just a sample; my real data set will have >3000 rows. I understand I will need to use malloc() for this when I run my real data, correct?
#user3629249 thank you and #Cool Guy for all your comments. Here's what I have now. I think sprintf() is still having trouble converting my array values back to a float. I've searched all over and I still cant tell what I doing wrong but the error is telling me that data[l][k] and todata are still incompatible, could you tell me if I'm on the right track and what I'm doing wrong with the sprintf() function?
#include <stdio.h>
int main() {
FILE *fp;
fp=fopen("airvariablesSend.csv", "r");
if(fp == NULL){
printf("cannot open file\n\n");
return -1;
}
// Headers removed for simplicity. Still found in airvariables.csv to see which //column means what
float data[9][6]; //for putting into array
int k , l;
float num; //for using getline() function
char *memory;
int nbytes = 500;
// space for using malloc? Is this enough or too much?
char *token; //for parsing through line using strtok()
char *search = ","; //delimiter for csv
char *todata; //for
//asking for space on heap
memory = (char *) malloc (nbytes + 1);
// Don;t need to use realloc() because getline() does it automatically? //http://crasseux.com/books/ctutorial/getline.html
for(k = 0; k < 6 ; k++) //repeats for max number of columns
{
for (l=0; l< 9; l++) //modify for number of rows that you have
{
num = getline (&memory, &nbytes, fp); //reading line by line
token = strtok(num, search); //separating lines by comma in csv
//Apparently strtok() will only use whitespace and I'm getting warnings here too. Is there another function for separating by commas?
sprintf(todata, "%f", token);
data[l][k] = todata;
printf("%f\n", data[l][k]);
}
}
fclose(fp);
free(memory);
return 0;
}
Change
for (l=1; l< 11; l++)
To
for (l=0; l< 10; l++)
And
printf("%f\n", data[10][7]);
To
printf("%f\n", data[l][k]);
And move the printf just after
data[l][k] = num;
The former is done because array indices start from 0 and end at length-1.
The latter is done because you need to loop through the array to get each value that is stored in each index of the array and print it. You can't just use data[10][7] and expect the whole array to be printed. data[10][7] is an invalid location and accessing it invokes Undefined Behavior which means that anything can happen including segmentation faults, runtime errors, crashes etc.
Also, add a return -1; in the end of the body of the first if to end the execution of the program if the fopen failed to open its first argument.

read text file and store in array in c programming

I want read text file and store in array then show.
This is my code:
int i = 0, line = 5;
char ch[100];
FILE *myfile;
myfile = fopen("test.txt","r");
if (myfile== NULL)
{
printf("can not open file \n");
return 1;
}
while(line--){
fscanf(myfile,"%s",&ch[i]);
i++;
printf("\n%s", &ch[i]);
}
fclose(myfile);
return 0;
}
This is my text:
test 123562
856
59986
But result:
est
2356
56
9986
What is wrong? :(
ch[i] is holding a single character. Statement fscanf(myfile,"%s",&ch[i]); will scan string to ch[i] which can hold only one character. There is no place for '\0' which leads your program to undefined behavior.
Change
fscanf(myfile,"%s",&ch[i]);
to
fscanf(myfile,"%s",ch);
Previous answer was wrong. Behavior of program is well defined but you are scanning the file in a wrong manner. Your program will work as expected if you place i++; after printf statement.
while(line--){
fscanf(myfile,"%s",&ch[i]);
printf("\n%s", &ch[i]);
i++;
}
The reason is that &ch[i] is a pointer to the ith element of the array and string will be stored in array starting at position i. For the input given, this will work because the given array is large enough to hold the string.
You can do this as:
while(line--){
fscanf(myfile,"%s",ch);
printf("\n%s", ch);
i++;
}
but it will overwrite the array ch each time a string is scanned to it. Better to use a two dimensional array to store strings and read file with fgets.
You're not going to be able to fit five lines in the single char ch[100] array; that's just an array of 100 characters.
You can make it an array of arrays, i.e. char ln[5][100] which will give you room for five lines of 100 characters each.
Then you of course need to index into that array in the loop, i.e.:
for(int i = 0; i < 5; ++i)
{
if(fgets(ln[i], sizeof ln[i], myfile) == NULL)
{
fprintf(stderr, "Read error on line %d\n", i);
exit(1);
}
}
This uses fgets() which is much better suited at reading in whole lines; fscanf() will stop at whitespace with %s which is seldom what you want.
There is no need to use the ampersand in the scanf while getting the string. Make that into like this.
fscanf(myfile,"%s",&ch[i]);
to
fscanf(myfile,"%s",ch);
&ch[i] It will get the character for i th position in that array. If you want to get like that you can use the %c instead of %s. And change this one to.
printf("\n%s", ch);
While printing the string when you use the ampersand(&) that will access the address of that variable.
The program developed must be able to read the input files containing matrix A and matrix B
using fopen function
a. Matrix A and B of different size may be stored in different input file (if required).
Scan and assign matrix A and B as array using fscanf function and for loop
Perform matrix operations
a. Add matrix A and B
b. Subtract matrix A and B
c. Multiply matrix A and B
Use conditional statement if or switch for switching between 3, 4 and 5 elements matrix.
Print all input matrices and results obtained in a new file called output.dat using fprintf
function.
The output.dat file must have a header with the following information:
a. Student name
b. Student matric number
c. Class section
d. Lecturer name
e. Project title
Below the header, the output file must contain matrix A and B and the results from matrix
operation.
Use matrix A and B as given below:

Strange output at after copy an array of char from a pointer to a line file

I am trying to read and store the data at some file (I have another program that tells me how many rows and columns I have). Now I am trying store the data at the file using a bidimensional array, a pointer and fgets.
#include <stdio.h>
#include <string.h>
int main (void)
{
int i=0,b=0;
char value[1024][3];
char (*p)[3] = value;
char line[1024];
FILE *fp=fopen("text.txt", "r");
if(fp==NULL){
printf("\nThe file does not exist\n");
}
else{
while( fgets ( line, sizeof(line), fp ) != NULL )
{
strcpy(p[i],line);
printf ("%s",p[i]);
printf("\n");
i++;
}
printf ("%s",value[0]);
printf("\n");
}
return 0;
}
From what I know ( and I know I am wrong… because I have an strange output ). p points to value and then I use strcpy to copy the content from line(1) to p(1) and value[lenght][1].
The output inside the while is ok p[0] prints the correct numbers, also p[1], and so on. When I try to print the value outside the loop (to verify) I get an strange output.
The file is ASCII and his content is ( no lines, they represent a tab):
1-2-3-44
2-33-4-5
22-3-5-12
The print at the while shows the next( no lines, they represent a tab):
1-2-3-44
2-33-4-5
22-3-5-12
The print outside shows the next:
1-22-322-3-5-12
Prints the first two numbers of the 1 row, the first two numbers of the second row and the complete third row. However if I change p[0] to p[2] prints the third row without errors:
22-3-5-12
You probably want three rows of 1024 chars.
With this char value[1024][3]; you have 1024 rows of 3 chars.
Switch the height and width of the array value and pointer p.

Resources