c, 2d char array and fopen - c

I'm trying to make a program that reads a file with list of names. The number of those names can vary, as well as the names lengths. I want to store them in an array of arrays of char, and read each row as a string to later open the file that corresponds to the name in question. But when I try to open the first one, I have an error opening file.
I'm totally out of ideas.
Help, please?
Here is the code relevant to this action:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int glimps(char *fname);
int write_av(char *fname, int NumbFiles);
int clr(char *fname);
int readFile(char *fname, int i);
double *dalpha, *alpha, *Ln_t, *LnLnA, Conc;
long *time, *weights, *Lmax, Nmax;
char *av_file, **in_files, *antetka;
/****************************************************************************/
int main(int argc, char *farg[])
{
int i, NumbFiles, flag;
long row;
char *a1;
FILE *fp;
av_file = farg[1];
printf("av_file = %s\n",av_file);
NumbFiles = glimps(av_file);
in_files = (char **) malloc (sizeof(char *) * NumbFiles);
for (i=0 ; i<NumbFiles ; i++)
in_files[i] = (char *) malloc (sizeof(char) * 200);
Lmax = (long *) calloc((size_t) NumbFiles, sizeof(long));
if((in_files == NULL)||(Lmax==NULL)) printf("Грешка при read алок.\n, "), exit(-1);
if (flag = readFile(av_file, -1))
printf("Error in read av_file %s\n", av_file), exit(-1);
weights = (long *) calloc((size_t) Nmax, sizeof(long));
for(i = 0; i<Nmax; i++) weights = 0;
for(i = 0; i<NumbFiles; i++)
{
//if (flag = readFile(&(*in_files[i]), i))
if (flag = readFile(in_files[i], i))
printf("Error in in_files[%d], %s\n",i, &(*in_files[i])), exit(-1);
}
if (flag = write_av(av_file, NumbFiles))
printf("Error in write_av(%s)\n,", av_file), exit(-1);
exit(0);
}
/****************************************************************************/
int glimps(char *fname)
{
FILE *fp;
char buf[140];
int cnt=0;
fp = fopen (fname, "r");
while (fgets(buf,140,fp) )
{
cnt++;
}
fclose(fp);
return (cnt);
}
/****************************************************************************/
int readFile(char *fname, int k)
{
int cnt=0;
FILE *fp;
char buf[200], dummy[13];
printf("fname is %s\n", fname); getchar();
fp = fopen (fname, "r");
if(fp==(NULL)) return(-1);
if(!strcmp(fname,av_file) )
{
while (fgets(in_files[cnt++],200,fp) );
}
else
{
printf("read TUK!\n"); getchar();
fgets(buf,200,fp);
sscanf(buf,"%s %s %s %s %s %s %s %ld %s %s %lf\n",
dummy, dummy,dummy,dummy,dummy,dummy,dummy, &Lmax[k],
dummy, dummy, &Conc);
fgets(buf,200,fp);
sscanf(buf,"%s\n", antetka);
printf("read TUK!\n"); getchar();
while (fgets(buf,200,fp))
{
sscanf(buf,"%ld %lf %lf %s %lf %lf\n",
&time[cnt], &dalpha[cnt], &alpha[cnt], dummy, &Ln_t[cnt],
&LnLnA[cnt]);
weights[cnt++]++;
}
}
fclose(fp);
return (0);
}
...
Console Output:
> ./avr alpha_cubeL.C0.010
av_file = alpha_cubeL.C0.010
fname is alpha_cubeL.C0.010
fname is alpha_cubeL100C0.010
Error in read in_files[0], alpha_cubeL100C0.010
> ls alpha_cubeL100C0.010
alpha_cubeL100C0.010

What happens is that in the readFile function, you read the main file given as argument to make (from the content) several file names in in_files[i], but fgets reads lines including the CR or CRLF (ie the end of line character(s)). Thus later in the program, readFile fails as it tries to open filename + CR [LF].
You may just add a trim function near the top of your program, like
void trim(char *s) {
int i,l = strlen(s);
for (i=l-1 ; i>=0 && (s[i]==10 || s[i]==13) ; i--) s[i] = 0;
}
that removes CR and/or LF that end a string s, and then change the readFile function to trim the file names read in each line, like
while (fgets(in_files[cnt++],200,fp) ) {
trim(in_files[cnt-1]); // cnt-1, or do the cnt++ here (and not above...)
}
Then the files can be opened...
(this is probably not the only problem in this program, but this is a good start)

Related

Why is fscanf() seg faulting while trying to read from a file?

I am using C in Visual Studio via a remote Linux server. I want to read a file and store the contents in a array of structs. Every time I try to read a line using fscanf() it seg faults. Thanks in advance.
Format of the file I'm trying to read:
F150 5.4 28000 white
RAM1500 5.7 32000 orange
car 4.5 12000 green
truck 6.1 55000 black
Here's a simplified version my program as the other parts function fine:
#include <stdlib.h>
#include <stdio.h>
struct data {
char name[20];
float floatNum;
int intNum;
char color[20];
} temp;
int scan(void) {
int size = 0;
FILE *data;
data = fopen("./hw3.data", "r");
while (1) {
fscanf(data, "%s %f %d %s", temp.name, &temp.floatNum,
&temp.intNum, temp.color);
if (feof(data))
break;
size++;
}
return size;
}
void load(int size, struct data autos[]) {
int i;
FILE *data;
data = fopen("./hw3.data", "r");
for (i = 0; i < size; i++) {
fscanf(data, "%s %f %d %s", autos[i].name, &autos[i].floatNum,
&autos[i].intNum, autos[i].color);
}
}
int main() {
int size;
struct data *autos;
size = scan();
autos = malloc(size * sizeof(struct data));
load(size, autos);
return 0;
}
There are multiple possible causes for problems:
you do not test if fopen() succeeds: if the file cannot be opened, the FILE pointer data will be null, causing undefined behavior in fscanf(), possibly a seg fault.
you do not test if malloc succeeds... again causing a seg fault if memory cannot be allocated.
you should close the FILE after reading
your test for feof() is incorrect: it might be true after successfully reading the last item, causing it to be ignored and you might never reach the end of file if one of the items cannot be read. You should just test the return value of fscanf(): it returns the number of successful conversions, so 4 in your case.
you should use %19s to avoid writing beyond the end of the targets arrays, another potential source of undefined behavior.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {
char name[20];
float floatNum;
int intNum;
char color[20];
};
int scan(const char *filename) {
struct data temp;
int size = 0;
FILE *data = fopen(filename, "r");
if (data == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
while (fscanf(data, "%19s %f %d %19s",
temp.name, &temp.floatNum,
&temp.intNum, temp.color) == 4) {
size++;
}
fclose(data);
return size;
}
int load(const char *filename, int size, struct data autos[]) {
int i;
FILE *data = fopen(filename, "r");
if (data == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
for (i = 0; i < size; i++) {
if (fscanf(data, "%19s %f %d %19s",
autos[i].name, &autos[i].floatNum,
&autos[i].intNum, autos[i].color) != 4)
break;
}
fclose(data);
return i;
}
int main() {
char filename[] = "./hw3.data";
int size = scan(filename);
if (size < 0)
return 1;
if (size > 0) {
struct data *autos = malloc(size * sizeof(struct data));
if (autos == NULL) {
fprintf(stderr, "cannot allocate %zu bytes\n", size * sizeof(struct data));
return 1;
}
int n = load(filename, size, autos);
for (int i = 0; i < n; i++) {
printf("%s %g %d %s\n", autos[i].name, autos[i].floatNum,
autos[i].intNum, autos[i].color);
}
free(autos);
}
return 0;
}

Save structure function leaves a spare place in a file instead of writing an array

#include <stdio.h>
struct BirdHome{
char area[500];
char heightcm[100];
char feederquantity[10];
char hasNest[5];
};
struct Bird{
char isRinged[5];
char nameSpecies[50];
char birdAgeMonths[500];
struct BirdHome hom;
char gender[6];
};
struct Bird birds;
int main(void){
FILE *oput;
int max=100;
int count = 0;
char filename[100];
printf("file name? : ");
scanf("%s", &filename);
count = load(filename, &birds, max);
if (count == 0)
printf("No structures loaded\n");
else (
printf("Data loaded\n")
);
save(&birds, oput);
return 0;
}
int load(char *filename, struct Bird *birds, int max){
int count = 0;
FILE *fp = fopen(filename, "r");
char line[100 * 4];
if (fp == NULL)
return 1;
while (count < max && fgets(line, sizeof(line), fp) != NULL){
sscanf(line, "%s %s %s %s %s %s %s %s", birds[count].isRinged, birds[count].nameSpecies,
birds[count].birdAgeMonths, birds[count].hom.area,
birds[count].hom.heightcm, birds[count].hom.feederquantity,
birds[count].hom.hasNest,birds[count].gender);
count++;
}
fclose(fp);
return count;
}
int save (struct Bird *birds, FILE *oput){
int i;
oput=fopen("birdssave.txt","w");
for (i=0;i<3;i++){
fprintf(oput,"%s %s %s %s %s %s %s %s\n",birds[i].isRinged, birds[i].nameSpecies,
birds[i].birdAgeMonths, birds[i].hom.area,
birds[i].hom.heightcm, birds[i].hom.feederquantity,
birds[i].hom.hasNest,birds[i].gender);
}
fclose(oput);
}
Well, the problem was said in the description of the question. Somehow, the load function works properly (at least I think so, because it runs properly and the success message is always displayed) and the save function runs without errors, but it doesn't write the needed info inside a file and just leaves gaps.
True sparrow 3 30 20 2 False Male
False crane 24 200 100 6 True Female
False griffin 14 300 80 1 False Male
This is a text file which my program used to write and load. I think this can somehow help you to find my mistakes in this code.
The load function is made unproperly so it doesn't work. The normal functions does a lot more things to do. Here is the text of it with the needed commentaries
int load(char * filename){
FILE * fp;
char *c;
int m = sizeof(int);
int n, i;
/*prepare memory for info*/
int *pti = (int *)malloc(m);
if ((fp = fopen(filename, "r")) == NULL){
perror("Error occured while opening file");
return 1;
}
/*read the quantity of structures*/
c = (char *)pti;
while (m>0){
i = getc(fp);
if (i == EOF) break;
*c = i;
c++;
m--;
}
/*get the number of elements*/
n = *pti;
/*prepare memory for read massive of structures*/
struct bird * ptr = (struct bird *) malloc(3 * sizeof(struct bird));
c = (char *)ptr;
/*after save we read massive by symbols*/
while ((i= getc(fp))!=EOF){
*c = i;
c++;
}
/*sort the elements and printing in console*/
printf("\n%d birds in the file stored\n\n", n);
for (int k = 0; k<n; k++){
printf("%d %s %s %d %d %d %d %s %s \n", k + 1,
ptr[k].isRinged,ptr[k].nameSpecies,ptr[k].birdAgeMonths,ptr[k].homearea,
ptr[k].homeheightcm,ptr[k].homefeederquantity,ptr[k].homehasNest,ptr[k].gender);
}
free(pti);
free(ptr);
fclose(fp);
return 0;
}
At least, the save function can be untouched only because algorhytmically it does the same as the normal code.

Read in the contents of a tab delimited text file and save into a single array in C

I am trying to read in the contents of a file using command line arguments to read the file and then store all contents of the file into a single array.
Keep in the mind, the file being read in is actually a matrix with the first row being an integer value designating the square size of the matrix and the following rows and columns being the matrix.
so far I have been able to dynamically allocate memory and then read the contents of the file using fgets. I am kind of stumped when it comes to storing the contents into a single array to access later. I tried using a double variable to hold the parsed contents of the 2nd while loop but when printed to the terminal it only gave me the last variable in the file.
I have attempted using strdup to make a copy of the string but am running into an error that says a value of type char cannot be stored in an entity of type char
here is my code.
If someone could help me, I would be very grateful.
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char **argv){ //char **argv will be used to read the input file
int i,j,k,l,m,nn;
long size;
double mat;
char *buff;
char n[100];
char *file = argv[1];
long len =0;
int h =0;
FILE *output; // need to declare the output file
FILE *f =fopen(file, "rb+"); //utilize argv to read in file, will read file in as binary file to obtain ASCII
fseek(f, 0L, SEEK_END); //Want to determine the size of the file to create a buffer
size = ftell(f); //Will seek to the end of the file, declare that position as the size
rewind(f); //Will rewind to the beginning of the file
buff = (char *)malloc(size); //Declare the buffer size from fseek
//Will read in and print out the contents of the file using fgets and printf
while(fgets(buff,size - 1,f) != NULL){
printf( "%s\n", buff);
}
rewind(f);
while(fscanf(f, "%lf", &mat) ==1){
buff[h] = _strdup(n);
h++;
}
printf("matrix stored is %c\n",mat);
Here's an example:
/*
* EXAMPLE FILE:
* 3,3
* 1,2,3
* 4,5,6
* 7,8,9
*
* EXAMPLE OUTPUT:
* #/rows=3, #/columns=3
* 1.000000, 2.000000, 3.000000
* 4.000000, 5.000000, 6.000000
* 7.000000, 8.000000, 9.000000
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define MAXLINE 100
#define DELIMITER ","
void print_matrix (int nrows, int ncols, double **mat) {
int i, j;
printf("#/rows=%d, #/columns=%d\n", nrows, ncols);
for (i=0; i < nrows; i++) {
for (j=0; j < ncols-1; j++) {
printf("%lf, ", mat[i][j]);
}
printf("%lf\n", mat[i][j]);
}
}
int main(int argc, char *argv[]) {
FILE *fp = NULL;
int iret = 1, n = 0, nrows, ncols;
double **mat, d;
char *s, line[MAXLINE], *endptr;
int i, j;
/* Read .csv filepath from cmd-line */
if (argc < 2) {
printf ("USAGE: app <fname>\n");
goto the_end;
}
/* Open file */
if (!(fp = fopen (argv[1], "r"))) {
printf ("File open(%s) failed: errno= %d\n",
argv[1], errno);
goto the_end;
}
/* Read matrix dimensions */
iret = fscanf(fp, "%d,%d", &ncols, &nrows);
if (iret != 2) {
printf ("Unable to read file dimensions, iret= %d, expected 2\n",
iret);
goto the_end;
}
/* Flush the extraneous newline left in the read buffer after fscanf()... */
fgetc(fp);
/* Allocate space for our matrix */
mat = (double **)malloc(sizeof(double *)*nrows);
if (!mat) {
printf ("Memory allocation error #matrix, errno=%d: exiting progam\n",
errno);
goto the_end;
}
for (i=0; i < nrows; i++) {
mat[i] = malloc(sizeof(double)*ncols);
if (!mat[i]) {
printf ("Memory allocation error #matrix[%d], errno=%d: exiting progam\n",
i, errno);
goto the_end;
}
}
/* Populate the matrix */
for (i=0; i < nrows; i++) {
++n;
s = fgets(line, MAXLINE, fp);
if (s == NULL) {
printf ("fgets read error, line %d, errno=%d: exiting program\n",
n, errno);
goto the_end;
}
s = strtok(line, DELIMITER);
for (j=0; j < ncols; j++) {
d = strtod(s, &endptr);
if (s == endptr) {
printf ("strtod(%s) conversion error, errno %d: exiting program\n",
s, errno);
goto the_end;
}
mat[i][j] = d;
s = strtok(NULL, DELIMITER);
}
}
/* Print the matrix */
print_matrix (nrows, ncols, mat);
/* Set "OK" status */
iret = 0;
the_end:
if (fp)
fclose(fp);
printf("Done: status=%d (%s)\n",
iret,
(iret == 0) ? "Status: OK" : "Status: FAIL");
return iret;
}

Seg fault from within my print function after reading in a file in c

I have an unknown segfault within my print function when I call it in main and I can't see what the obvious fix is. I have put printf's throughout the program and it doesn't print 'here4' making me think it's due to my print function, or when I call it in main.
I want to read a dictionary file into an array of strings.
Here is a snippet of the code:
Any ideas would be greatly appreciated, thanks.
#define PRIME 1009
void fileRead(int argc, char **argv)
void printTable(int arrayLength, char **table);
int main(int argc, char **argv)
{
char **table;
FILE *fp;
int i, arrayLength = PRIME;
/* Initial memory allocation */
table = (char**)malloc(PRIME*sizeof(char));
fileRead(argc, argv);
printf("here3\n");
for(i = 0; i < arrayLength; i++) {
printTable(arrayLength,table);
}
printf("here4\n");
return 0;
}
void fileRead(int argc, char **argv)
{
FILE *fp;
char *word;
int arrayLength = PRIME;
word = calloc(MAXCHAR, sizeof(char));
fp = fopen (argv[1], "r");
printf("here1\n");
/*read in grid and move along a cell each time */
while (fscanf(fp, "%s", word)!= EOF) {
if (argc != (2)) {
fprintf(stderr, "Cannot open file, %s\n Try again e.g. %s dictionary.txt\n" , argv[1], argv[0]);
}
if(fp == NULL) {
fprintf(stderr, "Cannot open file, %s\n Try again e.g. %s dictionary.txt\n" , argv[1], argv[0]);
return;
}
if (fp == NULL) {
fprintf(stderr, "Error opening file, try file name dictionary.txt\n");
exit(EXIT_FAILURE);
}
}
printf("here2\n");
fclose(fp);
return;
}
void printTable(int arrayLength, char **table)
{
int i;
for(i = 0; i < arrayLength; i++) {
printf("%s\n", table[i]);
}
printf("\n");
}
Let me summarize your code:
you allocate uninitialized memory for table
You call a function fileRead():
Allocate some memory for word
read the file
Do nothing with the data read.
fileRead() does nothing useful: It does not return anything, it doesn't touch table, is vulnerable to a buffer overflow of word and leaves the memory leak of word behind.
And then you printf the unchanged and uninitialized content of table
try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRIME 1009
#define MAXCHAR 256
char **fileRead(FILE *fp, int *len);
void printTable(int arrayLength, char **table);
int main(int argc, char **argv){
if (argc != 2) {
fprintf(stderr, "Need dictionary file argument.\nTry again e.g. %s dictionary.txt\n" , argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen (argv[1], "r");
if(fp == NULL) {
fprintf(stderr, "Cannot open file, %s\nTry again e.g. %s dictionary.txt\n" , argv[1], argv[0]);
exit(EXIT_FAILURE);
}
int arrayLength = PRIME;
char **table = fileRead(fp, &arrayLength);//fclose(fp) inside this
printTable(arrayLength, table);
for(int i = 0; i < arrayLength; ++i)
free(table[i]);
free(table);
return 0;
}
char **fileRead(FILE *fp, int *len){
char *word = calloc(MAXCHAR, sizeof(char));
char **table = malloc(*len * sizeof(char*));
int i = 0;
while (i < *len && fscanf(fp, "%s", word) != EOF){
table[i] = malloc(strlen(word)+1);
strcpy(table[i++], word);
}
fclose(fp);
*len = i;
free(word);
return table;
}
void printTable(int arrayLength, char **table){
int i;
for(i = 0; i < arrayLength; i++) {
printf("%s\n", table[i]);
}
printf("\n");
}

C - Opening differents files using same pointer

I'm trying to retrieve informations by many plain-text files, which will be then stored in a proper struct. To do so, I'm using a function that takes member of the struct to populate and source of the plain-text file where the informations are stored.
Posting my "test" code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct _elem
{
const char *title;
int ok;
int almost;
int nope;
int hits;
float last_rank;
};
typedef struct _elem Chapter;
Chapter *generate_array(const char *source, int *elems);
int engine_start(Chapter *elem, char *source);
int main()
{
const char path_f[100];
int elements = 0;
int i = 0;
Chapter *dict;
printf("Insert the name of the source:\n");
scanf("%s", path_f);
printf("\nGenerating dictionary, please wait...\n");
dict = generate_array(path_f, &elements);
if (dict == NULL)
{
printf("Aborting.\n");
exit(1);
}
while (i < elements)
{
printf("Element %d:\n", (i + 1));
printf("\nTitle: %s\n", dict[i].title);
printf("Ok: %10d\n", dict[i].ok);
printf("Almost: %5d\n", dict[i].almost);
printf("Nope: %8d\n", dict[i].nope);
printf("Hits: %8d\n", dict[i].hits);
printf("Rank: %8.2f\n", dict[i].last_rank);
printf("\n");
i++;
}
return EXIT_SUCCESS;
}
Chapter *generate_array(const char *source, int *elems)
{
FILE *src;
int sources;
int i = 0;
char **srcs;
Chapter *generated;
src = fopen(source, "r");
if (src == NULL)
{
printf("[!!] Error while reading file!\n");
return NULL;
}
fscanf(src, "%d", &sources);
if (sources <= 0)
{
printf("[!!] Wrong number of sources, exiting.\n");
return NULL;
}
srcs = (char **) malloc(sizeof(char *) * sources);
while (i < sources && !feof(src))
{
srcs[i] = (char *) malloc(sizeof(char) * 100);
fscanf(src, "%s", srcs[i++]);
}
fclose(src);
generated = (Chapter *) malloc(sizeof(Chapter) * i);
*elems = i;
i = 0;
while (i < *elems)
{
if(engine_start( &generated[i], srcs[i] )) i++;
else
{
printf("[!!] Error in file %s, aborting.\n", srcs[i]);
return NULL;
}
}
return generated;
}
int engine_start(Chapter *elem, char *source)
{
FILE *parser;
int done = 0;
parser = fopen(source, "r");
if (parser == NULL) printf("[!!] Error while opening %s, aborting.\n", source);
else
{
fgets(elem->title, 100, parser);
fscanf(parser, "%d %d %d %d %f", &(elem->ok), &(elem->almost),
&(elem->nope), &(elem->hits),
&(elem->last_rank) );
fclose(parser);
done = 1;
}
return done;
}
Now this is the main file where are stored paths to the other plain-text files:
lol.dat
5
lold/lol1.dat
lold/lol2.dat
lold/lol3.dat
lold/lol4.dat
lold/lol5.dat
And one example of lolX.dat:
Qual'è la vittoria di cristo?
3 4 5 12 44.9
I'm getting SIGSEGV after the first iteration of "engine_start", probably due to FILE *parser (but I can be totally wrong, I don't know at this point).
Someone can guide me through this problem? Thank you.
Make the following changes and try-
struct _elem
{
char *title; // allocate the memory for this.
int ok;
int almost;
int nope;
int hits;
float last_rank;
};
You need to allocate memory for element title before assigning something to it.
int engine_start(Chapter *elem, char *source)
{
FILE *parser;
int done = 0;
parser = fopen(source, "r");
if (parser == NULL) printf("[!!] Error while opening %s, aborting.\n", source);
else
{
elem->title=(char *)malloc(100); // include this line.
fgets(elem->title, 100, parser);
fscanf(parser, "%d %d %d %d %f", &(elem->ok), &(elem->almost),
&(elem->nope), &(elem->hits),
&(elem->last_rank) );
fclose(parser);
done = 1;
}
return done;
}

Resources