Home > Back-end >  Can anyone help? I am trying to read data from a file but its just spitting out garbage
Can anyone help? I am trying to read data from a file but its just spitting out garbage

Time:10-04

I am trying to read from file hw4.data and see if it has a name. The user inputs the name via a command line argument. Everything works fine but I can't get the file to be passed between the functions correctly. The assignment requires that I define the file in main and pass it between SCAN and LOAD.

#include <stdio.h>
#include <stdlib.h>

struct _data {
    char name[20];
    long number;
};

int SCAN(FILE *(*stream)) { // skim through the file and find how many entries there are
    int size = 0;
    char s_temp[100];
    long l_temp;
    while (1) {
        fscanf(*stream, "%s %ld", s_temp, &l_temp);
        if (feof(*stream)) break;
        size  ;
    }
    return size;
}

struct _data* LOAD(FILE *stream, int size) { // loop through the file and load the entries into the main data array
    struct _data* d = malloc(size * sizeof(struct _data));
    int i;
    for (i = 0; i < size; i  ) {
        fscanf(stream, "%s %ld", d[i].name, &d[i].number);
    }
    return d;
}

void SEARCH(struct _data *BlackBox, char* name, int size) { // loop through the array and search for the right name

    int i;
    int found = 0;
    for (i = 0; i < size; i  ) {
        printf("%s %s\n", BlackBox[i].name, name);
        if (strcmp(BlackBox[i].name, name) == 0) {
            printf("*******************************************\nThe name was found at the %d entry.\n*******************************************\n", i);
            found = 1;
            break;
        }
    }
    if (found == 0) {
        printf("*******************************************\nThe name was NOT found.\n*******************************************\n");
    }
}

void FREE(struct _data* BlackBox, int size) { // free up the dynamic array
    free(BlackBox);
}

int main(int argv, char* argc[]) {
    
    if (argv == 2) {
        printf("The argument supplied is %s\n", argc[1]);

        FILE* file = fopen("./hw4.data", "r");

        int size = SCAN(&file);
        struct _data* data = LOAD(&file, size);

        SEARCH(data, argc[1], size);

        fclose(file);
        return 0;
    } else {
        printf("*******************************************\n* You must include a name to search for.*\n*******************************************\n");
        return 0;
    }
}

Here's the format of hw4.data

ron 7774013
jon 7774014
tom 7774015
won 7774016

CodePudding user response:

A few issues:

  1. In SCAN, remove the feof. Replace with: if (fscanf(*stream, "%s %ld", s_temp, &l_temp) != 2) break;
  2. Note that after calling SCAN, you should do: rewind(file);. Otherwise, LOAD will only see [immediate] EOF.
  3. And, as others have mentioned, just pass file to SCAN/LOAD and not &file.
  4. Add a check for null return from fopen (e.g.) if (file == NULL) { perror("fopen"); exit(1); }

Stylistically:

  1. If you have a comment describing a function, put it on the line above the function.
  2. Try to keep lines within 80 chars

Here is the refactored code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct _data {
    char name[20];
    long number;
};

// skim through the file and find how many entries there are
int
SCAN(FILE *stream)
{
    int size = 0;
    char s_temp[100];
    long l_temp;

    while (1) {
        if (fscanf(stream, "%s %ld", s_temp, &l_temp) != 2)
            break;
        size  ;
    }

    return size;
}

// loop through the file and load the entries into the main data array
struct _data *
LOAD(FILE *stream, int size)
{
    struct _data *d = malloc(size * sizeof(struct _data));
    int i;

    for (i = 0; i < size; i  ) {
        fscanf(stream, "%s %ld", d[i].name, &d[i].number);
    }

    return d;
}

// loop through the array and search for the right name
void
SEARCH(struct _data *BlackBox, char *name, int size)
{

    int i;
    int found = 0;

    for (i = 0; i < size; i  ) {
        printf("%s %s\n", BlackBox[i].name, name);
        if (strcmp(BlackBox[i].name, name) == 0) {
            printf("*******************************************\n");
            printf("The name was found at the %d entry.\n", i);
            printf("*******************************************\n");
            found = 1;
            break;
        }
    }
    if (found == 0)
        printf("*******************************************\n"
            "The name was NOT found.\n"
            "*******************************************\n");
}

// free up the dynamic array
void
FREE(struct _data *BlackBox, int size)
{
    free(BlackBox);
}

int
main(int argv, char *argc[])
{

    if (argv == 2) {
        printf("The argument supplied is %s\n", argc[1]);

        FILE *file = fopen("./hw4.data", "r");
        if (file == NULL) {
            perror("fopen");
            exit(1);
        }

        int size = SCAN(file);
        rewind(file);
        struct _data *data = LOAD(file, size);

        SEARCH(data, argc[1], size);

        fclose(file);
    }
    else
        printf("*******************************************\n"
            "* You must include a name to search for.*\n"
            "*******************************************\n");

    return 0;
}

Using realloc, we can combine SCAN and LOAD into a single function:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct _data {
    char name[20];
    long number;
};

// loop through the file and load the entries into the main data array
struct _data *
LOAD(FILE *stream, int *sizep)
{
    struct _data *all = NULL;
    struct _data *d;
    int size = 0;
    int capacity = 0;

    while (1) {
        if (size >= capacity) {
            capacity  = 10;
            all = realloc(all,sizeof(*all) * capacity);
            if (all == NULL) {
                perror("realloc");
                exit(1);
            }
        }

        d = &all[size  ];

        if (fscanf(stream, "%s %ld", d->name, &d->number) != 2)
            break;
    }

    // trim to size actually used
    all = realloc(all,sizeof(*all) * size);

    *sizep = size;

    return all;
}

// loop through the array and search for the right name
void
SEARCH(struct _data *BlackBox, char *name, int size)
{

    int i;
    int found = 0;

    for (i = 0; i < size; i  ) {
        printf("%s %s\n", BlackBox[i].name, name);
        if (strcmp(BlackBox[i].name, name) == 0) {
            printf("*******************************************\n");
            printf("The name was found at the %d entry.\n", i);
            printf("*******************************************\n");
            found = 1;
            break;
        }
    }
    if (found == 0)
        printf("*******************************************\n"
            "The name was NOT found.\n"
            "*******************************************\n");
}

// free up the dynamic array
void
FREE(struct _data *BlackBox, int size)
{
    free(BlackBox);
}

int
main(int argv, char *argc[])
{

    if (argv == 2) {
        printf("The argument supplied is %s\n", argc[1]);

        FILE *file = fopen("./hw4.data", "r");
        if (file == NULL) {
            perror("fopen");
            exit(1);
        }

        int size;
        struct _data *data = LOAD(file, &size);

        SEARCH(data, argc[1], size);

        fclose(file);
    }
    else
        printf("*******************************************\n"
            "* You must include a name to search for.*\n"
            "*******************************************\n");

    return 0;
}

CodePudding user response:

I had to use rewind() in order to reset the file so that LOAD() would read from the start of the file and give good data.

  • Related