Creating an array with unknown size of input files - c

I newer in C language. I could not solve my problem. I have a input file, let's say input.txt. We know there are 4 column on every line. Nevertheless, we do not know how many lines are there. I give you sample input.txt:
Student,James,12,65
Teacher,Jane,23,60
Teacher,Michael,30,75
Student,Erric,15,73
First column can be 2 different things like student or teacher. 2nd column will be unique. No repeated names. 3rd column will be ages of the person's. 4th column will be weights. Also, I am trying to make 2D array. So, my goal is:
arrName = {{Student, James, 12, 65}, {Teacher,Jane,23,60}, {Teacher,Michael,30,75}, {Student, Erric, 15,73}}
I am trying to create like this array. The array must be dynamically. because we do not know how many lines are there. I could not split the every line by commas. I have tried strdot. how can I parse the lines with comma, and add them into 2D array? Also, I got confused about pointers. While creating 2D array, do we have to use like char **arrPtr;? Or using like *arrPtr is enough for creating 2D array?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COLUMN 4 //We know that there are 4 column in chars.txt file.
int main(int argc, char const *argv[]) {
char *arrName;
int nameLines;
arrName = (char *) malloc( sizeof( char ) );
FILE *FileName;
FileName = fopen(argv[1], "r");
if (FileName == NULL) {
printf("The Name file could not open!\n");
exit(0);
}
else{
char c;
while ( (c == fgetc(FileName)) != EOF ) {
if (c == '\n') {
nameLines++;
}
}
printf("%d\n", nameLines);
}
return 0;
}
I could not continue after else statement. Can you help me?

You got a bunch of errors in your code like this for example.
while ( (c == fgetc(FileName)) != EOF ) { -> Comparison of constant -1 with boolean expression is always true
So let's start fresh. This is how I would read a comma separated file and dynamically allocate memory to an array of ´read´ objects. It's actually less lines of code then you would expect.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COLUMNS 4
#define MAX_STRING_LENGTH 100 //Enter the maximum characters allowed as profession and name
typedef struct theDAta{
char type[MAX_STRING_LENGTH+1];
char name[MAX_STRING_LENGTH+1];
unsigned int age;
unsigned int weight;
}theData;
int main(int argc, char const *argv[]) {
theData* allDataPtr=malloc(1); //Pointer to all entries
theData currentData; //The current read data
int currentBlock=0; //the index currently 'active'
FILE *fp = fopen(argv[1], "r");
if (!fp) {
printf("The file you provided can't be read!\n");
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%[^,],%[^,],%d,%d\n", currentData.type, currentData.name,&currentData.age,&currentData.weight) == COLUMNS) {
allDataPtr=realloc(allDataPtr, sizeof(theData)*(currentBlock+1));
if (!allDataPtr) {exit(EXIT_FAILURE);} //Memory allocation failure. Ok so here i lost my pointer to the previous memory.. However we let the OS garbage collect us.
memcpy(allDataPtr+currentBlock++, &currentData, sizeof(currentData));
}
for (int x=0; x<currentBlock; x++) {
printf("Profession: %s\nName: %s\nAge: %d\nWeight: %d\n\n",allDataPtr[x].type,allDataPtr[x].name,allDataPtr[x].age,allDataPtr[x].weight);
}
fclose(fp);
free(allDataPtr);
return 0;
}
So what I do is to create a struct containing the stuff I want to populate from the file. Then I populate that object and extend the memory with the size of that object and then copy the read data to the end of that memory block.. That's basically it... Hope you get great grades :) !!
/Anders
EDIT
Was a bit bored this evening, so let's shave the code... And humm, well. This is not part of my official answer :-) but you could bling it like this (it's actually also skipping one layer of memory copy :) and the engine is 3 lines of C code if you define a line of C code delimiter as ';'->
typedef struct j{
char t[MAX_STRING_LENGTH+1];
char n[MAX_STRING_LENGTH+1];
unsigned int a;
unsigned int w;
}j;
int main(int argc, char const *argv[]) {
j* g;
int l=0;
FILE *h;
if((!(h=fopen(argv[1],"r"))||(!(g=malloc(sizeof(j))))))exit(-1);
while(fscanf(h,"%[^,],%[^,],%d,%d\n",g[l].t,g[l].n,&g[l].a,&g[l].w)==COLUMNS)if(!(g=realloc(g,sizeof(j)*(++l+1))))exit(-1);
for(int x=0;x<l;x++)printf("Profession: %s\nName: %s\nAge: %d\nWeight: %d\n\n",g[x].t,g[x].n,g[x].a,g[x].w);
fclose(h);
free(g);
return 0;
}

Related

Structures Program not working as intended (Bug)

I have been working on reading data from a file, which contains student name and age in the format:
John
12
Jane
13
Julia
18
Here's the program I wrote:
#include <stdio.h>
#include <stdlib.h>
struct record{
char name[50];
int age;
};
int main(){
FILE *fp;
fp=fopen("sample2.txt","r");
struct record a[50];
int counter=1;
int i=0;
while (!EOF){
if (counter%2!=0){
fgets(a[i].name,50,fp);
counter++;
}
if (counter%2==0){
a[i].age=getw(fp);
counter++;
i++;
}
}
return 0;
}
However, on printing a[0].name, I am not getting expected output. Can someone help?
As already pointed out in the comments, EOF is a value defined in stdio.h and does not say anything about your file descriptor. I also would recommend you to use fscanf (As long you are sure that the names in the file are all of the correct length). fscanf takes a string similar to printf, specifying the elements you are expecting and returns the number of possible matches. Also it helps you with converting your data to the correct datatypes. So the code could look like this:
#include <stdio.h>
#include <stdlib.h>
struct record
{
char name[50];
int age;
};
int main ()
{
FILE *fp;
fp = fopen ("sample2.txt", "r");
struct record a[50];
int i = 0;
while (fscanf(fp, "%s\n%d\n", (char *) a[i].name, &a[i].age) > 0) {
i++;
}
printf("%s %d\n", a[1].name, a[1].age);
return 0;
}

C function returning different values while calling from main function

I have written a program which read values from a the file. The data in the file is in following format.
100 Full Name SomeDetails.
234 Full Name SomeDetails
Following is the program which i wrote.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define MAX 10
struct student
{
int rollno;
char name[20];
char course[25];
};
int main()
{
FILE *fptr;
fptr=fopen("records.txt","r");
struct student s[10];
int i=0,tstudent=0;
char che;
char line[100];
//SECTION : 1.1 -> READING NUMBER OF LINES
while(!feof(fptr))
{
che=fgetc(fptr);
if(che=='\n')
{
tstudent++;
}
}
printf("Total Lines in File = %d\n",tstudent);
fclose(fptr);
//SECTION : 1.2 -> READING RECORDS FROM FILE
fptr=fopen("records.txt","r");
char newString[20][20];
int ii,j,ctr;
j=0;
ctr=0;
for(i=0; i<tstudent; i++)
{
fgets(line,100,fptr);
printf("Value of Line %d = %s",i,line);
for(ii=0; ii<=(strlen(line)); ii++)
{
// if tab or NULL found, assign NULL into newString[ctr]
if(line[ii]=='\t'||line[ii]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=line[ii];
j++;
}
}
}
for(ii=0; ii < ctr; ii++)
{
printf("\n%s",newString[ii]);
}
printf("Value of ctr = %d",ctr);
fclose(fptr);
}
Above code is working fine, BUT all the code is in main function, but i want to make a separate function which can be called from main file and return me every data of file in two dimensional or one dimensional array as return value.
Any help/suggestions would be appreciated.
I tried following CODE as a separate function.. NOT WORKING.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
char readfile(int tstudent,FILE* filename)
{
//FUNCTION TO READ RECORDS FROM FILE.
FILE *fptr;
int i,k;
char line[100];
char newString[20][20];
int j=0,ctr=0;
fptr=fopen("records.txt","r");
for(i=0; i<tstudent; i++)
{
fgets(line,100,fptr);
printf("Value of Line %d = %s",i,line);
for(k=0; k<=(strlen(line)); k++)
{
// if tab or NULL found, assign NULL into newString[ctr]
if(line[k]=='\t'||line[k]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=line[k];
j++;
}
}
}
return newString;
}
I defined a new variable char results[] in main function.. and tried to called the function as follows
results[]=readfile(tstudent,fptr)
but when trying to read results.. its showing garbage
char readfile(int tstudent,FILE* filename)
...
char newString[20][20];
...
return newString;
That can't be a good thing, right? You define readFile to return one single character (not a pointer, just one byte) and then return an array instead. We should not be surprised the compiler complained.
If you "fix" that be redefining the return type, you still have a problem because newString is an automatic local variable. The storage (memory) it defines is undefined outside the function.
The easiest way for a function to populate a structure (or array) in C is for the caller to pass it as a function parameter. So you wind up with something more like:
int readfile( FILE* input, char newString[][20], int tstudent )
where newString is defined the same way as you have it, but by the caller, not in readfile. Cf. the stdio functions like fgets; most of them require the caller to define the buffer they read into.
I'll just point out a few more mistakes.
Whenever you call a function -- especially an I/O function -- check for errors. You may want to read tstudent records, but how many are there? If you ask for 5 and find only 1, what then? Your read loop must test for end-of-file, and readfile must return the number of records read, else the caller will never know. Compare with how fread(3) works. Those Unix guys knew a thing or two about how to define a function!
Now your function looks something like this:
int readfile( FILE* input, char newString[][20], int tstudent ) {
char line[100], *s;
int i=0;
for( ; i < tstudent && (s = fgets(line, sizeof(line), input)) != NULL; i++ ) {
/* do stuff with line */
}
/* check for EOF/error if s is NULL, and report */
return i;
}

Getting wrong output from reading lines in a file in c program

I need to get this output:
P1 0 3
P2 1 6
P3 4 4
P4 6 2
But instead I am getting this:
0 0 0
0 0 0
0 0 0
0 0 0
I am new to C programming. So, I don't know why I am getting wrong output. This is what I did. I am supposed to store each column in different variable. Because After storing them in different variable I need to do maths calculation for them.
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
int main (int argc, char *argv[]) {
FILE *fptr;
fptr = fopen(argv[1], "r");
if (fptr != NULL) {
size_t i;
int SIZE = 1000;
int*x[500];
int*y[500];
int*z[500];
int ch=0;
int l;
int n=0;
char line[100];
while ((ch=fgetc (fptr))!= EOF) {
if (ch=='\n')
n++;
}
printf("Number of lines = %d\n", n);
for (l=0; l<n;++l) {
while(fgets(line,sizeof line,fptr)) {
printf("%s",line);
sscanf(line,"%d %d %d",&x[l],&y[l],&z[l]);
}
}
for (i=0; i<l;++i) {
printf("%d %d %d\n",x[i],y[i],z[i]);
}
fclose(fptr);
return 0 ;
}
I see at least 2 issues.
The fptr has gone to the end of file while counting number of lines. So rewind() the fptr after counting lines, as it has gone up to the end of file. So add rewind(fptr) after first while loop.
You do not need x, y, z as array of pointers, rather just an array. So change them to
int x[500];
int y[500];
int z[500];
Okay, lets sort this out with comments first:
#include<stdio.h>
// i dont think the following includes are nessesary for the given code
//#include<stdlib.h>
//#include <string.h>
//#include <math.h>
//#include <stdint.h>
//#include <stdbool.h>
int main (int argc, char *argv[]) {
FILE *fptr;
// i wonder a little about what youre opening here with argv[1]
// since arrays start counting at 0
// for testing and more understandability maybe just put the file
// where your code is and deliver its filename as a string?
fptr = fopen(argv[1], "r");
if (fptr != NULL) {
// whats that? you use it as a counting variable, make it int
// not size_t
size_t i;
// its not good practive to have a variable in capitals
// if you wanna make it a constant, you should define it
// at the beginning of the code, right after your includes
int SIZE = 1000;
// dont use pointers (these -> "*") here! Maybe you mix up
// dynamic array declaration (which requires using malloc() and
// no brackets like "int * dynArray;") with static arrays
// correct usage would be: int x[500]; thats it
int*x[500];
int*y[500];
int*z[500];
int ch=0;
// just a hint for more readability: use "j" instead of "l" but
// thats really up to you :D
int l;
int n=0;
char line[100];
// here you loop through your file char by char and just count
// the lines. Why dont pick the chars on the fly and actually
// write something into your defined arrays x, y, z ?
// some additional conditions (if) may do the trick
while ((ch=fgetc (fptr))!= EOF) {
if (ch=='\n')
n++;
}
printf("Number of lines = %d\n", n);
// sizeof is a function, so youre missing the parentheses
// and above that, you already know the size of your line array
// because its statically defined to hold 100 * sizeof(char)
// my suggestion: trash this entire loop and rethink the previous
for (l=0; l<n;++l) {
while(fgets(line,sizeof line,fptr)) {
printf("%s",line);
sscanf(line,"%d %d %d",&x[l],&y[l],&z[l]);
}
}
// cool loop. but there was no input to x, y, z except the first
// element of your line array, which seems to hold just a 0
// so everythings correct here, the mistake occured before
for (i=0; i<l;++i) {
printf("%d %d %d\n",x[i],y[i],z[i]);
}
//nice, thats important :)
fclose(fptr);
return 0 ;
}
i hope it helps you sort out things and may guide to a clearer question which maybe answeres itself? :D

Reading .csv file into an array in C [duplicate]

This question already has answers here:
Read .csv file in C
(6 answers)
Closed 6 years ago.
I am Currently trying to read a .csv file into an array in C. I'm somewhat on the fence on how to approach the problem. I've looked through many forums and related topic but I still can't grasp it. If someone could show me or break it down as simple as possible. That would be greatly appreciated. By the way, the contents of the .csv file is like this. The array should consist of just the alphabet and the number. I was thinking about using a 2-D array. Is that an appropriate solution?
A,1
B,2
C,3
....
Start by defining your data structure:
struct my_record {
char name;
int value;
};
Then you can read like this:
FILE* my_file = fopen(...);
struct my_record records[100];
size_t count = 0;
for (; count < sizeof(records)/sizeof(records[0]); ++count)
{
int got = fscanf(my_file, "%c,%d", &records[count].name, &records[count].value);
if (got != 2) break; // wrong number of tokens - maybe end of file
}
fclose(my_file);
Now you have a 1D array of structs, one for each row.
You can just create an array of structs, as the other answer described.
Once you have the struct definition:
typedef struct {
char letter;
int number;
} record_t;
Then you can create an array of structs like this:
record_t records[26]; /* 26 letters in alphabet, can be anything you want */
Using a 2D array would be unnecessary, as wrapping the letter and number in a struct would be easier to handle.
In terms of reading your file, you can just read with fscanf() until 2 values are not found.
Here is some basic code you can use:
#include <stdio.h>
#include <stdlib.h>
#define NUMLETTERS 26
typedef struct {
char letter;
int number;
} record_t;
int main(void) {
FILE *fp;
record_t records[NUMLETTERS];
size_t count = 0;
fp = fopen("letters.csv", "r");
if (fp == NULL) {
fprintf(stderr, "Error reading file\n");
return 1;
}
while (fscanf(fp, " %c,%d", &records[count].letter, &records[count].number) == 2) {
count++;
}
for (size_t i = 0; i < count; i++) {
printf("%c,%d\n", records[i].letter, records[i].number);
}
fclose(fp);
return 0;
}

Segmentation fault with arrays and pointers

I have a segmentation fault...i'm not sure what's causing it. Also, when passing the member pname into the function get_names, am I doing this correctly, or is there a better way of doing this?
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
void get_names (int count, char *str);
int main (void) {
int i;
for (i = 0; i < MAX_PLAYRS; i++) {
get_names(i, &(*player[i].pname));
printf("Player: %s\n", player[i].pname);
}
}
void get_names (int count, char *str) {
FILE *inp;
char status;
inp = fopen("teamnames.rtf", "r");
status = fscanf(inp, "%s", str);
if (status == EOF) {
count = MAX_PLAYRS;
}
}
With your code unchanged, I get a segmentation fault if the file can't be opened properly (i.e. it's unreadable due to permissions, or it simply does not exist).
Here's a modified version of you function get_names():
void get_names(int count, char *str)
{
FILE *inp;
inp = fopen("teamnames.rtf", "r");
if (inp == NULL) {
perror("Failed");
return;
}
fgets(str, MAX_NAME, inp);
fclose(inp);
}
This would still read the first name 16 times, but it would tell you why it didn't manage to open the file. To read the next name from the file (rather than repeatedly the first name), open (and close) the file in the main() function instead.
Also, you might as well call get_names() like so:
get_names(i, player[i].pname);
No need to do that &(*...) thing you're doing.
And, finally, I hope that the teamnames.rtf file is not actually an RTF file, but a simple text file with a name on each line.
The problem comes from this line:
get_names(i, &(*player[i].pname));
Understanding pointers and dereferencing is one of the biggest adjustments to learning C if you are switching from another language. You're doing it wrong, and I think you should seek out a tutorial on the subject. Try http://www.cplusplus.com/doc/tutorial/pointers/ as a starting point.
Get a debugger to tell you what is wrong. Compile the code with debugging enabled (see you man page for your compiler) and run something like this:
gdb a.out core
Then you should be able to see which line made the code core dump. You could use idb as well, if you have the intle compiler installed. This is, of course, on *nix. If you are talking windows, use the VS debugger.
In addition do NOT use fscanf as it is unsafe. Use fgets instead.
There are many strange things. First thing is, it seems like the names are in a file, but what you are doing is in every iteration of your for loop, you call get_names which opens the file again, that is goes to the beginning of the file and you read the same name over and over again.
That is if you closed the file. Since you haven't closed the file, the file is already open and you keep reopening it (which could be the cause of your problem)
Another thing is, how can
if (status == EOF) {
count = MAX_PLAYRS;
}
Give you the current count? Regardless of the count of the players in the file, you are just setting it to MAX_PLAYERS.
Another thing is that count is an input to the function that is not a pointer, so setting it does not change the value outside the function (which is what I assumed you wanted).
Here is how I would do it with minimum change to your code:
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
void get_names (int count, char *str, FILE *inp);
int main (void) {
FILE *inp;
int i;
int count;
inp = fopen("teamnames.rtf", "r");
for (i = 0; i < MAX_PLAYRS; i++) {
get_names(&count, player[i].pname, inp);
printf("Player: %s\n", player[i].pname);
}
}
void get_names (int *count, char *str) {
char status;
status = fscanf(inp, "%s", str);
if (status == EOF) {
*count = MAX_PLAYRS;
}
}
Here is how I would do it more concisely:
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
int get_names (Team_t *team);
int main (void) {
get_names(player);
}
int get_names (Team_t *team) {
int i = 0;
FILE *inp;
inp = fopen("teamnames.rtf", "r");
while (i < MAX_PLAYRS && !feof(inp) {
fscanf(inp, "%s", team[i].pname);
printf("Player: %s\n", player[i].pname);
}
}
Note that the problems with fscanf, checking array boundaries etc are not the concern of this solution, but this rather gives you the idea of what to do not a code for you to copy-paste.

Resources