Reading CSV into C Struct - c

I'm trying to read a CSV into a struct in C. I need to read in an item name, its weight and its value. They are listed straight through in the CSV i.g (name, name, name, ..., weight, weight, ..., value, value, ..).
#include <stdio.h>
typedef struct {
char name[25];
double weight;
double value;
} Item;
int main() {
// Open data.csv
FILE *packingList;
packingList = fopen("data.csv", "r");
// Check for proper file Opening
if (packingList == NULL) {
printf("File did not open correctly.\n");
return 1; // Signal error
}
// Declare array of items to store data
Item items[100];
for (int i = 0; i < 3; i++)
{
fscanf(packingList,
"%24[^,]",
items[i].name);
printf("| %s | ", items[i].name);
}
fclose(packingList);
return 0;
}
csv
MRE1,MRE2,MRE3,MRE4,PolyPro,HygieneKit,PoopyWipes,Gloves,ExtraSocks1,ExtraSocks2,ExtraSocks3,Snacks,JetBoil,Ammo1,Ammo2,M16,SleepingBag,BivvySack,GoreTex,E-Tool,Canteens,FlakJacket,FrontSAPIPlate,BackSAPIPlate,WarBelt,Compass,NVG,Bayonet,Diary,Iodine,Knife,Lamp,Nameplate,Ointment,Quiver,Radio,Toothbrush,Utensils,Vitamins,X-acto Knife,Yellow safety belt,Zinc-oxide
2.125,2,1.875,2,1.5,2.5,0.5,0.5,0.25,0.25,0.25,1.5,1,3,3.75,7,5,2.5,2.5,3,4.25,3,8.25,8,3.5,1.125,1.125,5,0.75,0.375,0.875,1.125,0.25,0.875,3.75,7.625,0.375,0.25,0.125,3.75,2.125,4.625
12,10,8,6,10,5,6.5,4.5,9,6,2,1.5,5,15,100,80,35,22,18,12,18,30,50,25,12,50,3,86,50,6,9,5,1,8,7,20,5,2,1,5,2,6
The code I'm running only reads in the first first 3 items as a test, but only properly gets the first item name, the other 2 come out as weird characters. How would I go about writing this to properly read the CSV and attach the appropriate weight and values to each item?
My Output
| MRE1 | | $5�� | | �¤ |

Consider reading the 3 lines using fgets() and then parse the lines. Unless 3 lines read, no point in parsing.
Then parse the 3 lines, one at a time or as a group, as shown below.
This sample code uses "%n" to detect the offset of the scan, if it got that far. Notice that the ',' is in the format.
Other code could use strtod(), strcspn(), strtok(), for parsing.
#define ITEM_N 100
#define NAME_SIZE 25
// Scale the max lines size in some fashion.
// I recommend 2x the maximum expected size.
#define LINE_SIZE ((ITEM_N * NAME_SIZE + 3)*2)
char lines[3][LINE_SIZE];
char *s[3];
int i;
for (i = 0; i < 3; i++) {
if (fgets(lines[i], sizeof lines[i], packingList) == NULL) {
break;
}
s[i] = lines[i];
}
if (i == 3) {
Item items[ITEM_N];
size_t index;
for (index = 0; index < ITEM_N; index++) {
int n = 0;
sscanf(s[0], "%24[^,]%*[,\n]%n", items[index].name, &n);
if (n == 0) break;
s[0] += n;
n = 0;
sscanf(s[1], "%lf%*[,\n]%n", &items[index].weight, &n);
if (n == 0) break;
s[1] += n;
// likewise for .value (not shown)
}
// Code can now use `index` items.
}

Related

random numbers being read into array instead of the text file values

I am trying to make a function that reads all the numbers from a text file into an array, where each line of the file has a number, ex:
57346
40963
24580
98307
98312
32777
10
16392
16396
...
My function does allocate the necessary size to store the values, but the values being stored are random ones and 0's that aren't in my text file. Output ex:
0
0
296386
0
-485579776
-653048057
584
0
2095946880
...
This is my code:
typedef struct set{
void** values;
int size;
}Set;
int checkSize(FILE* file) {
int counter = 0;
char chr;
chr = getc(file);
while (chr != EOF) {
if (chr == '\n') {
counter = counter + 1;
}
chr = getc(file);
}
return counter;
}
Set* readSet(FILE* file){
Set* new = malloc(sizeof(Set));
new->size = checkSize(file);
new->values = malloc(sizeof(void*)*new->size);
int arrayAux[new->size];
int i = 0, n;
while(i < new->size) {
fscanf(file, "%ld", &arrayAux[i]);
new->values[i] = arrayAux[i];
i++;
}
//loop to remove the first three lines of the file, which are the number of values in the file,
//the biggest value of the file and the division between the number of values and the biggest value
for(i = 0; i < 3; i++) {
new->values[i] = new->values[i + 1];
new->size--;
}
for (i = 0; i <= new->size; i++) {
printf("%d\n", new->values[i]);
}
return new;
}
How can I fix this? Thanks in advance for any help.
Why void and not long?
You cannot do int arrayAux[new->size]; as size is a variable and thus cannot be used at compile time !!! 100% guarantee of reading out of bounds.
Read the value from file into a long and assign it to the proper space in your list.
Why have the size in every row? Use a global int
why loop to step over the first three in the list?
size -=3
i+=3
Works just as well

Not able to print this 2D array (weird output) in C

I am trying to read a text file with 100 numbers like 1 2 45 55 100 text file here (all on a single line) and then put them in a 10x10 array (2D array).
736.2 731.6 829.8 875.8 568.3 292.2 231.1 868.9 66.7 811.9 292.0 967.6 419.3 578.1 322.5 471.7 980.0 378.8 784.1 116.8 900.4 355.3 645.7 603.6 409.1 652.1 144.1 590.6 953.1 954.0 502.0 689.3 685.6 331.9 565.1 253.9 624.1 796.2 122.8 690.7 608.0 414.8 658.3 27.3 992.9 980.8 499.0 972.8 359.7 283.1 89.7 260.1 638.4 735.4 863.6 47.5 387.5 7.7 638.1 340.6 961.7 140.1 29.8 647.3 471.9 594.9 901.2 96.0 391.1 24.0 786.7 999.1 438.7 445.0 26.4 431.6 425.9 525.4 404.4 785.6 808.5 494.1 45.7 447.0 229.5 909.3 494.4 617.0 917.0 132.5 957.5 878.8 272.6 987.4 526.1 744.5 582.3 427.3 840.5 973.3
Here is my code:
#include <stdio.h>
#define NR 10
#define NC 10
int main(void) {
int numbers[9][9];
int i = 0;
int count;
int j = 0;
FILE *file;
file = fopen("numbers.txt", "r");
for (count = 1; count < 101; count++) {
fscanf(file, "%d", &numbers[i][j]);
j++;
if ((count != 1) && (count % 10 == 0)) {
i++;
j = 0;
}
}
fclose(file);
int p = 0;
int q = 0;
for (p = 0; p < NR; p++) {
for (q = 0; q < NC; q++) {
printf("%d", numbers[p][q]);
}
printf("\n");
}
return 0;
}
As SparKot noted in a comment, to read a 10x10 matrix, you need to define the matrix with 10x10 elements:
int numbers[10][10];
That has to be one of the weirder ways of reading a 10x10 matrix that I've ever seen. Why not go for a simple approach of nested loops. Since the data contains floating-point numbers, you need to read them as double (or perhaps float) values.
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
double double_val;
if (fscanf(file, "%lf", &double_val) != 1)
{
fprintf(stderr, "failed to read matrix[i][j]\n", i, j);
exit(EXIT_FAILURE);
}
numbers[i][j] = double_val;
}
}
The mess with double_val works around the data containing floating point numbers and your original code trying to read integers. You'll get one valid value; thereafter, fscanf() will return 0 because the . is not a part of a valid integer. This highlights the importance of checking the return value from fscanf() and its relatives.
Frankly, you should be using double numbers[10][10]; for the data from the file. Then you could read directly into the array:
if (fscanf("%lf", &numbers[i][j]) != 1)
But you'd need to check (and probably change) all the rest of the code too.
There are multiple issues in your code:
the matrix is too small, make it numbers[NR][NC].
you do not check for fopen failure: you will have undefined behavior if the file numbers.txt is not in the current directory or cannot be open for reading.
you read the file contents as integers, but the file contains floating point numbers with a . decimal separator: the second and subsequent fscanf() will get stuck on the . and keep returning 0 without modifying the destination number, leaving the matrix mostly uninitialized. Make the matrix double numbers[NR][NC], read the numbers with %lf and test for conversion failure.
the counting method in the reading loop is weird. Just use 2 nested for loops with proper counter and tests.
printing the matrix contents, you should output at least a space between numbers so the output is readable.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define NR 10
#define NC 10
int main() {
double numbers[NR][NC];
FILE *file;
file = fopen("numbers.txt", "r");
if (file == NULL) {
fprintf(stderr, "cannot open numbers.txt: %s\n", strerror(errno));
return 1;
}
for (int i = 0; i < NR; i++) {
for (int j = 0; j < NC; j++) {
if (fscanf(file, "%lf", &numbers[i][j]) != 1) {
fprintf(stderr, "error reading number at row %d, col %d\n",
i + 1, j + 1);
fclose(file);
return 1;
}
}
}
fclose(file);
for (int p = 0; p < NR; p++) {
for (int q = 0; q < NC; q++) {
printf(" %5g", numbers[p][q]);
}
printf("\n");
}
return 0;
}
Clear all a common condition that causes programs to crash; they are often associated with a file named core.
code is showing segmentation fault.

Segmentation Fault when My Code Executes the printf() in c

below I have posted my code. When I compile I receive no errors, and only one warning about variables I haven't used yet. the code works all the way to the line in code where it starts to print. I have tested all the sections and I believe that one is at fault. please let me know what I am doing wrong so I can fix it.
#include <stdio.h>
#include <string.h>
#define NUM_LINES 37
#define LINE_LENGTH 60
void select_sort_str(char list[NUM_LINES][LINE_LENGTH], int n);
int alpha_first(char list[NUM_LINES][LINE_LENGTH], int min_sub, int max_sub);
int main (void){
//store each line in an array of strings
FILE *inp;
FILE *outp;
char hurr[NUM_LINES][LINE_LENGTH];
;
inp = fopen("hurricanes.csv","r");
outp = fopen("out.txt","w");
//read in lines from file
for (int i = 0; i<NUM_LINES; i++){
fgets(hurr[i], LINE_LENGTH, inp);
}
inp = fopen("hurricanes.cvs","r");
//printf("%s", hurr[0]);
//define function
select_sort_str(hurr, NUM_LINES);
return(0);
}
int
alpha_first(char list[NUM_LINES][LINE_LENGTH], // input - array of pointers to strings
int min_sub, // input - min and max subscripts of
int max_sub) // portion of list to consider
{
int first, i;
first = min_sub;
for (i = min_sub + 1; i <= max_sub; ++i) {
if (strcmp(list[i], list[first]) < 0) {
first = i;
}
}
return (first);
}
/*
* Orders the pointers in an array list so they access strings in
* alphabetical order
* Pre: first n elements of list reference string of uniform case;
* n >= 0
*/
void
select_sort_str(char list[NUM_LINES][LINE_LENGTH], // input/output - array of pointers being
// ordered to acces strings alphabetically
int n) // input - number of elements to sort
{
int fill, // index of element to contain next string in order
index_of_min; // index of next string in order
char *temp;
char temp1[NUM_LINES][LINE_LENGTH];
for (fill = 0; fill < n - 1; ++fill) {
index_of_min = alpha_first(list, fill, n - 1);
if (index_of_min != fill) {
temp = list[index_of_min];
list[index_of_min][LINE_LENGTH] = list[fill][LINE_LENGTH];
strncpy(temp1[index_of_min], list[index_of_min], LINE_LENGTH);
temp1[fill][LINE_LENGTH] = *temp;
}
}
char *name;
char *cat = 0;
char *date;
for (int i = 0; i<NUM_LINES; i++){
name = strtok(NULL, ",");
cat = strtok(NULL, "h");
date = strtok(NULL, " ");
printf("%s %s %s\n", name, cat, date);
}
// for( int i =0; i<NUM_LINES; i++){
// printf("%s", list[i]);
// }
}
The only first parameter you ever pass to strtok is NULL. You never actually give it anything to parse. Did you perhaps mean strtok(temp1[i], ",");?
Also, why no error checking? It's much easier to find bugs in code with error checking.

Attempting to read in a file and storing the first input in an array val and the second input in an array wt (weight)

I need to read in a file called "data.txt" and store the first input as a value and the second corresponding input as a weight. I'm having issues reading them in and storing the values.
data.txt (example)
3 25
2 20
1 15
4 40
5 50
This is what I´ve started with:
FILE *myFile;
myFile=fopen("data.txt", "r");
int val[20]={0}; //initialize value array to zero
int wt[20]={0};
int W=80; //Set capacity to 80
int i;
int n;
while(!feof(myFile)){
fscanf(myFile, "%1d%1d", &val[i], &wt[i]);
}
n = sizeof(val)/sizeof(val[0]);
printf("%d", knapSack(W, wt, val, n));//prints out the maximum value
fclose(myFile);
return 0;
I've edited the above code to the following:
FILE *myFile;
myFile=fopen("data.txt", "r");
int val[20]={0};
int wt[20]={0};
int W=80; //Set capacity to 80
int i;
int n;
for(i=0;i<sizeof(val);i++){
fscanf(myFile, "%1d%1d", &wt[i],&val[i]);
}
n = sizeof(val)/sizeof(val[0]);
printf("%d", knapSack(W, wt, val, n));//prints out the maximum value
fclose(myFile);
return 0;
It keeps outputting 55 when I use the inputs from the data.txt example.
The biggest problem you are having is you are not controlling your read-loop with the return of the read itself. For example, in your case you would want:
int i = 0;
while (fscanf(myFile, "%1d%1d", &wt[i],&val[i]) == 2)
i++;
At the end of your read, i would hold the number of elements read into your arrays.
(note: you cannot use any input function correctly unless you check the return...)
Instead of reading the values into separate arrays, whenever you are coordinating multiple values as a single object (e.g. each val and wt pair), you should be thinking struct. That allows you to coordinate both values as a single object.
A simple example in your case could be:
#include <stdio.h>
#define MAXVAL 20 /* if you need a constant, #define one (or more) */
typedef struct { /* struct with int val, wt + typdef for conveninece */
int val, wt;
} mydata;
int main (int argc, char **argv) {
size_t n = 0; /* number of elements read */
mydata arr[MAXVAL] = {{ .val = 0 }}; /* array of mydtata */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
/* read all pairs of values in file into array */
while (fscanf (fp, "%d %d", &arr[n].val, &arr[n].wt) == 2)
n++;
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < n; i++) /* output values */
printf ("arr[%zu] %2d %2d\n", i, arr[i].val, arr[i].wt);
}
Above, the code does the same as I suggested in conditioning the read-loop on successfully reading a pair of values from the file. The only difference is that is coordinates the val and wt values in a struct.
Example Use/Output
With your data in the file dat/val_wt.txt, you would receive the following output:
$ ./bin/read_val_wt dat/val_wt.txt
arr[0] 3 25
arr[1] 2 20
arr[2] 1 15
arr[3] 4 40
arr[4] 5 50
While above we read directly with fscanf, you can make your read a bit more robust by reading each line into a character array first, and then parsing the wanted values from the character array with sscanf. You are essentially doing the same thing, but by using fgets/sscanf you can make an independent validation of (1) the read of the line; and (2) the parse of the wanted information from the line. If you have a malformed-line, it prevents the matching-failure from impacting the read of the remaining lines in the input file.
Look things over and let me know if you have further questions.
Oops, many little problems here...
First even if unrelated, you consistenly fail to check the result of input functions. It can lead to hide problems...
Next, the rule is when you do not get what you would expect, trace intermediary values.
Had you happen those lines:
// uncomment next block for debugging
printf("n=%d\n);
for (i = 0; i < n; i++) {
printf("%d %d\n", wt[i], val[i]);
}
You would have seen
n = 20
3 2
5 2
2 0
1 1
5 4
4 0
5 5
0
showing that:
n was 20 (unsure whether you expected it)
you had read your values one digit at a time instead of one integer value (because of the %1d formats)
My advice:
for (i = 0; i<sizeof(val); i++) { // do not try to read more than array capacity
if (2 != fscanf(myFile, "%d%d", &wt[i], &val[i])) break; // stop when no more data
}
n = i; // number of actual values
// uncomment next block for debugging
/*
printf("n=%d\n);
for (i = 0; i < n; i++) {
printf("%d %d\n", wt[i], val[i]);
}
*/

Sorting Words and Numbers from a file in C

I have been tasked with writing a function that takes a string reference and an integer reference parameter. The function must scan a .txt file and set the reference parameters to the name of the player with the highest score and the corresponding score.
This is written in the scores.txt file I must reference:
Ronaldo
10400
Didier
9800
Pele
12300
kaka
8400
Cristiano
8000
I currently have this much coding wrote however I am stuck as to how I am suppose to match the names up with the score since they have to be in no particular order. Within my coding I sort the numbers from greatest to least but I am not sure if this is needed or not.
FILE *input;
char name[name_len];
double score[score_len];
int a;
int b;
double placeholder;
input = fopen("scores.txt", "r");
if (input == NULL)
{
printf("\n Cannot open scores.txt for input\n");
}
for (a =0; a < 5; ++a)
fscanf(input, "%s%lf", name, score);
for (a = 0; a < 5; ++a) /* Repeats the step until three numbers are sorted*/
{
for (b = a + 1; b < 5; ++b) /* Repeats until the last two numbers are sorted*/
{
if (score[a] < score[b]) /* Sorts the 3 numbers using a placeholder to exchange the numbers in the array*/
{
placeholder = score[a];
score[a] = score[b];
score[b] = placeholder;
}
}
}
fclose(input);
return 0;
Any help regarding the solution or how I can move forward is much appreciated.
You can just read the number and name in, and replace the value of the score and the name if its bigger.
char name[name_len];
double score[score_len];
char highScoreName[name_len];
double highScore = 0;
...
for (int a = 0; a < 5; ++a)
{
fscanf(input, "%s %lf", name, score[a]);
if (highScore < score[a])
{
highScore = score[a];
strcpy(highScoreName, name);
}
}

Resources