1

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.

  • Can you please elaborate exactly what errors or incorrect behaviours you are seeing? "having issues" is not a very informative description. What issues precisely? – kaylum Jan 27 '20 at 05:43
  • 2
    [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – kaylum Jan 27 '20 at 05:45
  • Thank you, It was not outputting anything so I assumed it was how I was storing val and wt from the file. – noobGirlCoding Jan 27 '20 at 05:48
  • You may make life easier with `struct mydata { int val; int wt; };` Then you can simply create your array `strct mydata arr[20] = {{ .val = 0; }};` Now you can coordinate each `val` and `wt` as a single object, e.g. `arr[0].val` and `arr[0].wt;`, etc..Read a line at a time with either `size_t n = 0; while (fscanf(myfile, "%d %d", &arr[n].val, &arr[n].wt) == 2) { n++; }` Now you have your filled array of struct and your number of elements `n`. – David C. Rankin Jan 27 '20 at 06:04
  • OT: regarding: `myFile=fopen("data.txt", "r");` always check (!=NULL) the returned value to assure the operation was successful. – user3629249 Jan 28 '20 at 07:14
  • this: `for(i=0;i – user3629249 Jan 28 '20 at 07:16
  • regarding: `while(!feof(myFile)){ fscanf(myFile, "%1d%1d", &val[i], &wt[i]); }` This neither initializes nor increments `i` so what ever random value in on the stack where `i` is located will be used – user3629249 Jan 28 '20 at 07:19
  • strongly suggest the `while()` loop use the returned value from `fscanf()` as the controlling value, not `feof()` – user3629249 Jan 28 '20 at 07:21
  • when asking a question about a run-time problem (as this question is doing) please post a [mcve] so we can reproduce the problem and help you debug it – user3629249 Jan 28 '20 at 07:23

2 Answers2

2

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.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
1

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]);
}
*/
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252