Splitting a long string - c

I have an archive results.csv and I need to read the first two lines of this archive, split the second one and print them out on output.txt. Somehow it's not printing anything, yet I don't know the reason.
I didn't add the functions that I'm sure are fine.
Command: a.c results.csv
First line:
date,home_team,away_team,home_score,away_score,tournament,city,country,neutral
Second line:
18721130,Scotland,England,0,0,Friendly,Glasgow,Scotland,FALSE
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
typedef struct
{
char *line1;
long int date;
char *h_team;
char *a_team;
int gols_h_team;
int gols_a_team;
char *reason;
char *city;
char *country;
char *neutral_field;
}Data;
void alloc_Data(Data *d, int size)
{
d->line1 = (char*)malloc(50*sizeof(char));
d->h_team = (char*)malloc(30*sizeof(char));
d->a_team = (char*)malloc(30*sizeof(char));
d->reason = (char*)malloc(30*sizeof(char));
d->city = (char*)malloc(30*sizeof(char));
d->country = (char*)malloc(30*sizeof(char));
d->neutral_field = (char*)malloc(9*sizeof(char));
}
void store(Data *d, FILE *input, FILE *output, int size)
{
fscanf(input, "%s", d[0].line1);
fprintf(output, "%s\n", d[0].line1);
for(int i = 1; i < size; i++)
{
fscanf(input, "%li,%[^,]s%[^,]s%d,%d,%[^,]s%[^,]s%[^,]s%[^,]s", &d[i].date, d[i].h_team, d[i].a_team, &d[i].gols_h_team, &d[i].gols_a_team, d[i].reason, d[i].city, d[i].country, d[i].neutral_field );
fprintf(output, "%li,%s,%s,%d,%d,%s,%s,%s,%s\n", d[i].date, d[i].h_team, d[i].a_team, d[i].gols_h_team, d[i].gols_a_team, d[i].reason, d[i].city, d[i].country, d[i].neutral_field );
}
}
int main(int argc, char *argv[])
{
FILE *input;
FILE *output;
char *string = "output.txt";
int size = 2;
open_input(argv, &input);
open_output(string, &output);
Data *d;
d = (Data*)malloc(size*sizeof(Data));
alloc_Data(d, size);
store(d, input, output, size);
free(d);
return 0;
}

OP's fscanf() format is messed up with an s after %[^,] and missing ,. #Gem Taylor
A better alternative is to read all lines using fgets(). (including the first)
// fscanf(input, "%li,%[^,]s%[^,]s%d,%d,%[^,]s%[^,]s%[^,]s%[^,]s",...d[i].neutral_field );
#define EXPECTED_MAX_BUFFER_SIZE 150
char buffer[EXPECTED_MAX_BUFFER_SIZE * 2]; // suggest using 2x expected max size
if (fgets(buffer, sizeof buffer, input)) {
Then parse the team results with sscanf(). Using a " %n" at the end is an easy way to test if the entire sscanf() succeeded with no extra junk. sscanf() deserve width limits and complex scans benefit with some defines to manage the specifiers. Notice no s after "%29[^,]"
int n = 0;
#define FDat "%li ,"
#define FScr "%d ,"
#define Ftxt " %29[^,],"
#define Fneu " %8[^,]"
sscanf(buffer, FDat Ftxt Ftxt FScr FScr Ftxt Ftxt Ftxt Fneu " %n",
&d[i].date, d[i].h_team, d[i].a_team,
&d[i].gols_h_team, &d[i].gols_a_team,
d[i].reason, d[i].city, d[i].country, d[i].neutral_field, &n);
if (n > 0 && buffer[n] == '\0') {
// success
fprintf(output, ...
} else {
// bad input
}

Related

C: Newbie attemping file reading and struct allocation using malloc

I am trying to store the values stored in a details.txt file into their appropriate place in a dynamically allocated struct. Am I doing something (that should be simple) incorrectly for this not to work? Is it necessary for me to use strtok and split by ','?
My details.txt reads:
mitch,8,1.78,burgers
murray,42,6.5,lasagna
travis,64,1.85,sushi
sam,12,1.94,bacon
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFERSIZE 256
typedef struct
{
char name[BUFFERSIZE];
int favnumber;
float height;
char favfood[BUFFERSIZE];
} Person;
void print_person(Person *p)
{
printf("name: %s\n", p->name);
printf("num: %d\nheight: %.2f\nfav. food: %s\n\n",
p->favnumber, p->height, p->favfood);
}
int count_lines(FILE *fp)
{
int nlines = 0;
char c;
for (c = fgetc(fp); c != EOF; c = fgetc(fp))
{
if (c == '\n')
{
nlines++;
}
}
rewind(fp);
return nlines;
}
int main(void)
{
FILE *fp = fopen("details.txt", "r");
// count lines
int nlines = count_lines(fp);
printf("found %d lines\n\n",nlines);
Person *people = (Person*)malloc(nlines*sizeof(Person));
char buffer[BUFFERSIZE];
int i = 0;
while (fgets(buffer,BUFFERSIZE,fp) != NULL)
{
sscanf(buffer,"%s%d%f%s",people[i].name,
&(people[i].favnumber),
&(people[i].height),people[i].favfood);
print_person(&(people[i]));
i++;
}
printf("found %d people\n",i);
free(people);
fclose(fp);
}
Unfortunately, the current output of my program is:
found 4 lines
name: mitch,8,1.78,burgers
num: 0
height: 0.00
fav. food:
...
found 4 people
The problem is that the first %s parse the the whole line, and you need , in the format string to separate the fields. Not an issue here yet but I also used %[^,] for the last format string so it will not stop at the first space. Also added precision on the strings to avoid buffer overflows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFERSIZE 255
#define str(s) str2(s)
#define str2(s) #s
typedef struct
{
char name[BUFFERSIZE+1];
int favnumber;
float height;
char favfood[BUFFERSIZE+1];
} Person;
void print_person(Person *p)
{
printf("name: %s\n", p->name);
printf("num: %d\nheight: %.2f\nfav. food: %s\n\n",
p->favnumber, p->height, p->favfood);
}
int count_lines(FILE *fp)
{
int nlines = 0;
char c;
for (c = fgetc(fp); c != EOF; c = fgetc(fp))
{
if (c == '\n') {
nlines++;
}
}
rewind(fp);
return nlines;
}
int main(void)
{
FILE *fp = fopen("details.txt", "r");
// count lines
int nlines = count_lines(fp);
printf("found %d lines\n\n",nlines);
Person *people = (Person*)malloc(nlines*sizeof(Person));
char buffer[BUFFERSIZE+1];
int i = 0;
while (fgets(buffer,BUFFERSIZE+1,fp) != NULL)
{
// Changed line, see formatting of %s
sscanf(buffer,
"%" str(BUFFERSIZE) "[^,],%d,%f,%" str(BUFFERSSIZE) "[^,]",
people[i].name,
&(people[i].favnumber),
&(people[i].height),people[i].favfood);
print_person(&(people[i]));
i++;
}
printf("found %d people\n",i);
free(people);
fclose(fp);
}

Segmentation Fault Dynamically allocated array of structures

I want to parse a .csv file of the form: grade(float), year(int), name(string), county(string), number(int) and I don't see my mistake:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 300
typedef struct{
char *name, *county;
float grade;
unsigned long int year, number;
}info;
int main(int argc, char **argv)
{
FILE *fin = fopen("lab3.txt", "r");
if(!fin)
{
fprintf(stderr, "ERROR OPENING THE FILE.\n");
exit(1);
}
char buf[MAX];
while(fgets(buf, MAX, fin))
{
buf[strcspn(buf,"\n")] = '\0'; // remove the trailing newline
char *fields[6], *word = strtok(buf, ",");
int i = 0;
while(word)
{
info *array = (info *)malloc(sizeof(info));
fields[i] = word;
array->name = strdup(fields[2]);
array->county = strdup(fields[3]);
array->grade = atof(fields[0]);
array->year = atoi(fields[1]);
array->number = atoi(fields[4]);
printf("Name : %s | County: %s | Year : %ld | Grade : %f | Number: %ld",array->name, array->county, array->year, array->grade, array->number);
//printf("Word : %s\n", fields[i]);
word = strtok(NULL,",");
i++;
free(array->county);
free(array->name);
free(array);
}
}
fclose(fin);
return 0;
}
There are exactly 5 fields on each line, so I wanted to break each line into words andI also used gdb to check what's wrong and the problem seems to be here array->name = strdup(fields[2]);. I've tried numerous things so far, I've allocated memory for the array and the name and county, I'm freeing the memory so, what's the mistake?
There are a number of issues.
You don't really need [nor want] either fields or word. You can just use realloc to increase the size of the array and operate on the current pointer directly.
Doing malloc(sizeof(char)), as you have it, just leaks memory because of the strdup after it.
You do not want to do free at the bottom of the loop--it just kills what you did strdup for.
You are not expanding the size of array on each iteration [using realloc], so your array size stays at one. And, you blow away the previous value on each iteration, so, again, you're leaking memory.
Here's a refactored version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 300
typedef struct {
char *name;
char *county;
float grade;
unsigned long int year;
unsigned long int number;
} info;
#define TOK \
({ \
cp = strtok(bp,","); \
bp = NULL; \
cp; \
})
#define SAVE_S(_sym) \
arrcur->_sym = strdup(TOK)
#define SAVE_F(_sym) \
arrcur->_sym = atof(TOK)
#define SAVE_I(_sym) \
arrcur->_sym = atol(TOK)
int
main(int argc, char **argv)
{
FILE *fin = fopen("lab3.txt", "r");
if (!fin) {
fprintf(stderr, "ERROR OPENING THE FILE.\n");
exit(1);
}
char buf[MAX];
info *arrbase = NULL;
int arrcnt = 0;
int arrmax = 0;
char *bp;
char *cp;
while (fgets(buf, MAX, fin)) {
// remove the trailing newline
buf[strcspn(buf, "\n")] = '\0';
// enlarge array -- use of arrmax limits number of realloc calls
if (arrcnt >= arrmax) {
arrmax += 100;
arrbase = realloc(arrbase,sizeof(*arrbase) * arrmax);
}
// point to current array entry
info *arrcur = &arrbase[arrcnt];
bp = buf;
SAVE_S(name);
SAVE_S(county);
SAVE_F(grade);
SAVE_I(year);
SAVE_I(number);
printf("Name : %s | County: %s | Year : %ld | Grade : %f | Number: %ld",
arrcur->name, arrcur->county, arrcur->year, arrcur->grade,
arrcur->number);
++arrcnt;
}
fclose(fin);
// trim to size used
arrbase = realloc(arrbase,sizeof(*arrbase) * arrcnt);
return 0;
}

Storing input from file into struct in C

So I have an input file that I'm scanning in. I also have an array of structs. I need to store the information from this input into the structs. I'm able to read the input file and print it back out but im not sure how to go about storing this information in my structs. The issue seems to be that I can't access my structs properly in the function that scans the file. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* make an array of structs that contain the ponds, and the ponds contain pointers to the circular lists */
struct pond_struct {
char name[20];
int sequence;
int failfish;
int eatingcounter;
int threshold;
struct pond_struct *next;
struct pond_struct *prev;
};
typedef struct pond_struct pond;
struct pond_list_struct {
pond *head;
pond *tail;
};
typedef struct pond_list_struct pond_list;
int get_number_of_ponds(FILE *ifp)
{
char s[128];
int num;
//get the first line of the file
fgets (s, 127, ifp);
if(isspace(s[0]))
{
fgets (s, 127, ifp);
}
sscanf(s, "%d", &num);
return num;
}
void remove_crlf(char *s)
{
char *t = s + strlen(s);
// t begins at the null sentinel at the end of s.
t--;
/* t is now at the last character of s - unless s didn't contain any characters, in which
case, t is now *BEFORE* s. We have to keep checking for that. */
/* We repeat until EITHER t slides to the left of s, OR we find a character that is not a
line feed (\n) or a carriage return (\r). */
while ((t >= s) && (*t == '\n' || *t == '\r'))
{
*t = '\0'; // Clobber the character t is pointing at.
t--; // Decrement t.
}
}
void get_next_nonblank_line(FILE *ifp, char *s, int max_length)
{
s[0] = '\0';
while (s[0] == '\0')
{
fgets(s, max_length, ifp);
remove_crlf(s);
}
}
void read_pond (FILE *ifp, FILE *ofp, pond ponds)
{
char s[128];
char full_line[128];
int nponds;
int i;
int pond_number;
char name[128];
//char sequence_string[128];
int sequence;
//char failfish_string[128];
int failfish;
//char eatingcounter_string[128];
int eatingcounter;
//char threshold_string[128];
int threshold;
nponds = get_number_of_ponds(ifp);
printf("There are %d ponds\n", nponds);
fprintf(ofp, "There are %d ponds\n", nponds);
for (i = 0; i < nponds; i++)
{
get_next_nonblank_line(ifp, full_line, 127);
sscanf(s, "%d %s %d %d %d", &pond_number, name, &failfish, &eatingcounter, &threshold);
printf("The pond name is %s\n", full_line);
}
}
/* void print_pond (FILE *ofp, pond ponds, char* name, int sequence, int failfish, int eatingcounter, int threshold)
{
fprintf(ofp, "%s is pond number %d. The number of failfish is %d, the eating counter is %d, and the threshold is %d\n", name, sequence, failfish, eatingcounter, threshold);
} */
int main (void)
{
FILE *ifp;
FILE *ofp;
int nponds;
int i;
char name[128];
int sequence;
int failfish;
int eatingcounter;
int threshold;
pond ponds[10];
// change input file name
ifp = fopen("input.txt", "r");
ofp = fopen("output.txt", "w");
read_pond(ifp, ofp, ponds[0]);
/* for (i = 0; i < nponds; i++)
{
print_pond(ofp, ponds[i], name, sequence, failfish, eatingcounter, threshold);
} */
fclose(ifp);
fclose(ofp);
return 0;
}
typedef struct {
int nMyInt;
char szDate[6];
char filler[2];
} _MY_STRUCT;
_MY_STRUCT stMS;
stMS.nMyInt = 2;
strcpy(stMS.szDate,"10/19/2020");
Update your structure so byte-alignment storage is 8 bytes using a filler.
Use &stMS with fread/fwrite and sizeof(_MY_STRUCT) to read/write data.

Error using fprintf and fscanf

I have an archive results.csv and I need to read the first line of this archive and print it out on output.txt. Somehow it's printing random characters after everything and I couldn't figure out what is wrong.
Command: a.c results.csv
First line:
date,home_team,away_team,home_score,away_score,tournament,city,country,neutral
output.txt: date,home_team,away_team,home_score,away_score,tournament,city,country,neutral,(!£,(!£,(!£,(!£,(!£,#,£,(!£,(!£
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
typedef struct
{
char *line1;
char *line1a;
char *line1b;
char *team1;
char *team2;
char *reason;
char *city;
char *country;
char *neutral_field;
}data;
void open_input(char *argv[], FILE **input)
{
if((*input=fopen(argv[1], "r")) == NULL)
{
printf("%s not found\n", argv[1]);
exit(1);
}
}
void open_output(char *string, FILE **output)
{
if((*output=fopen(string, "w")) == NULL)
{
printf("%s not found\n", string);
exit(1);
}
}
void alloc_data(data *d, int size)
{
d->line1 = (char*)malloc(4*sizeof(char));
d->team1 = (char*)malloc(9*sizeof(char));
d->team2 = (char*)malloc(9*sizeof(char));
d->line1a = (char*)malloc(10*sizeof(char));
d->line1b = (char*)malloc(10*sizeof(char));
d->reason = (char*)malloc(10*sizeof(char));
d->city = (char*)malloc(4*sizeof(char));
d->country = (char*)malloc(7*sizeof(char));
d->neutral_field = (char*)malloc(7*sizeof(char));
}
void store(data *d, FILE *input, FILE **output)
{
fscanf(input, "%s,%s,%s,%s,%s,%s,%s,%s,%s", d[0].line1, d[0].team1, d[0].team2, d[0].line1a, d[0].line1b, d[0].reason, d[0].city, d[0].country, d[0].neutral_field );
fprintf(*output, "%s,%s,%s,%s,%s,%s,%s,%s,%s\n", d[0].line1, d[0].team1, d[0].team2, d[0].line1a, d[0].line1b, d[0].reason, d[0].city, d[0].country, d[0].neutral_field );
}
int main(int argc, char *argv[])
{
FILE *input;
FILE *output;
char *string = "output.txt";
int size = 1000;
open_input(argv, &input);
open_output(string, &output);
data *d;
d = (data*)malloc(size*sizeof(data));
alloc_data(d, size);
store(d, input, &output);
free(d);
return 0;
}
fscanf(input, "%s,%s,%s,%s,%s,%s,%s,%s,%s", d[0].line1, d[0].team1,...
The above code tries to read the whole line in to d[0].line1 which causes buffer overflow. team1 and the rest will contain uninitialized data.
You have to change fscanf as follows:
fscanf(input, "%3[^ ,\n\t],%9[^ ,\n\t],...
Where 3 is 4 - 1, and 4 is the size of d[0].line1
Alternatively you can use strtok
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void store(FILE *input, FILE *output)
{
char buf[500];
while(fgets(buf, sizeof(buf), input))
{
//strip end-of-line from `buf`
if(strlen(buf))
if(buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0;
//tokenize with strtok
char *token = strtok(buf, ",");
while(token)
{
fprintf(output, "%s", token);
token = strtok(NULL, ",");
}
fprintf(output, "\n");
}
}
int main(int argc, char *argv[])
{
FILE *input = fopen("input.txt", "r");
FILE *output = fopen("output.txt", "w");
store(input, output);
return 0;
}
With above code you don't need an additional structure.
If you do use a structure for data, you have to be more careful. It seems you are trying to create an array of 1000 data, but the following only creates one oversized pointer, not an array of data
int size = 1000;
data *d;
d = (data*)malloc(size*sizeof(data));
alloc_data(d, size);
Additionally, for each malloc there should be a corresponding free.
Your buffers aren't big enough to hold the terminating NUL byte. scanf stores that NUL byte (overrunning the buffer), but then the object that really owns that byte may overwrite it, so when printf looks for the NUL it doesn't find it until much later in memory.
The buffer overruns are a bigger problem than what you've seen, who knows what objects those NUL bytes you didn't make space for are smashing? And what happens when you read a data file with slightly different header spelling? Suddenly your hard-coded allocations sizes will be even more wrong than they are already.

C segmentation fault xor char array

I want to xor a certain value on all of my chars in a char array. I have some code that works all fine except for the xor line:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void obfuscate(FILE *file, char *input, char *variableName)
{
int i;
int size = (int)strlen(input);
char a = 65;
fprintf(file, "%s: %s -> ", variableName, input);
for(i = 0; i < size; i++)
{
input[i] = (char)(input[i] ^ a);//I am causing a segmentation fault
fprintf(file, "0x%x, ", input[i]);
}
return;
}
int main()
{
char *a = "MyString";
FILE *file = fopen("out.txt", "w");
obfuscate(file, a, "a");
fclose(file);
}
I use the normal gcc compiler with gcc in.c -o out.o on a linux machine.
If I comment the line with the xor operation it works just fine. Any help is highly appreciated, my own research did not result in a solution.
Try below solution with dynamic memory.
In char *a = "MyString"; char *in = malloc(sizeof(a));
a is pointing to code section we can't alter it. &
in is pointing to heap section, so we can modify it any no.of times.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void obfuscate(FILE *file, char *input, char *variableName)
{
int i;
int size = (int)strlen(input);
char a = 65;
fprintf(file, "%s: %s -> ", variableName, input);
for(i = 0; i < size; i++)
{
input[i] = (char)(input[i] ^ a);//I am causing a segmentation fault
fprintf(file, "0x%x, ", input[i]);
}
return;
}
int main()
{
char *a = "MyString";
char *in = malloc(sizeof(a));
strcpy(in, a);
FILE *file = fopen("out.txt", "w");
obfuscate(file, in, "a");
fclose(file);
free(in);
}

Resources