1

I want to read data from txt file and save those data in variables not just print output. How do I save those data from text file in variables? I tried like this and it did not work out:

int value1 ; 
object2->value =&value1 ; 
*(object2->value) = value1 ; 

My txt file looks like this:

INT 
A
5

and my code looks like this:

#include <stdio.h>
#include <stdlib.h> // For exit()

struct variable {
    char type[10];
    char name[10];
    int value;
};

int main(){

struct variable *object2=malloc(sizeof(struct variable));

    FILE * file= fopen("input.txt", "rb");
    if (file != NULL) {
        fread(object2, sizeof(struct variable), 1, file);
        fclose(file);
    }
    
    int value1 ;
    object2->value =&value1 ;
    *(object2->value) = value1 ;

    printf("%d\n",value1);

    printf("%s/%s/%d\n",object2->type,object2->name,object2->value);
    
    
    }
  • 1
    Welcome to StackOverflow! Please take the [tour] and read "[ask]" to learn how this site works. -- Did you consider to use `fgets()` and `sscanf()` for the task? If you use `fread()`, you need your input file to be binary compatible to your structure layout. Commonly it cannot be a text file. -- Oh, and you did not ask a question. – the busybee Sep 05 '21 at 17:16
  • 1
    You stated your goal, but not your problem. You need to ask a specific question about what you're having trouble with. – Tom Karzes Sep 05 '21 at 17:43
  • @TomKarzes I dont know how to save these values in variables because I dont know how to dereference these pointers for example here I tried like this: int value1 ; object2->value =&value1 ; *(object2->value) = value1 ; and it didnt work –  Sep 05 '21 at 17:48
  • @PPProgramer Edit your post to include your question. – Tom Karzes Sep 05 '21 at 17:49
  • I will in a few seconds when I correct everything, I will include solution. I am new here so sorry for bad formating. –  Sep 05 '21 at 17:53
  • Is `int value1 = object2->value;` all you are asking for? That is just simple [assignment](https://en.cppreference.com/w/c/language/operator_assignment). The value of `object2->value` will be copied into `value1`. You already did this successfully when you copied the return value of calling `fopen` into the variable `file` - only difference is the types involved. – Oka Sep 05 '21 at 20:03

3 Answers3

2

File format:

CHAR
B
6
INT
A
5
FLOAT
C
7

This is my solution:

#include <stdio.h>
#include <stdlib.h> // For exit()
#include <string.h>

#define BUFF_SIZE 1024
#define NAME_TYPE_SIZE 10
#define VALUE_SIZE 20

#define NOT_ENOUGH_MEMORY 1
#define CANT_OPEN_FILE 2
#define FILE_ENDED 3
#define TOO_BIG_STR 4
#define CANT_FORMAT_VALUE 5
#define NOT_FOUND_LINE 6

#define SEARCH_NAME "A"

#pragma warning(disable : 4996) // for vs

struct variable {
    char type[NAME_TYPE_SIZE];
    char name[NAME_TYPE_SIZE];
    int value;
};

int find_var_in_file(char* file_path, char* find_name, struct variable* dest);

int main()
{
    struct variable* object2 = malloc(sizeof(struct variable));

    if (NULL == object2)
    {
        printf("not enough memory");
        return NOT_ENOUGH_MEMORY;
    }

    int error = find_var_in_file("input.txt", SEARCH_NAME, object2);

    if (CANT_OPEN_FILE == error)
    {
        return printf("can't open file");
    }

    if (error == 0)
    {
        // Printing data to check validity
        printf("read: type: %s name: %s value: %d", object2->type, object2->name, object2->value);
        int a = object2->value;
        // do stuff with a
    }
    else
    {
        if (error == NOT_FOUND_LINE)
        {
            printf("not find the var \"" SEARCH_NAME "\" in the file");
        }
        else
        {
            printf("error reading the file. error code: %d", error);
        }
    }

    free(object2);

    return 0;
}

int read_line(char* buffer, int buffer_size, char* dest, int dest_size, FILE* stream)
{
    if (!fgets(buffer, buffer_size, stream))
    {
        return NOT_FOUND_LINE;
    }

    int read_len = strlen(buffer);

    if ('\n' == buffer[read_len - 1])
    {
        if (read_len == 1)
        {
            return NOT_FOUND_LINE;
        }
        buffer[read_len - 1] = '\0'; // remove "\n" in the end
    }

    if (dest_size <= strlen(buffer)) // last chat is null
    {
        return TOO_BIG_STR;
    }

    strcpy(dest, buffer);

    // clear the read
    memset(buffer, '\0', read_len);

    return 0;
}

int find_var_in_file(char* file_path, char* find_name, struct variable* dest)
{
    char file_buffer[BUFF_SIZE] = { 0 }; // Buffer to store data
    FILE* stream = fopen(file_path, "r");
    if (NULL == stream)
    {
        return CANT_OPEN_FILE;
    }

    int error = 0;
    while (1)
    {
        // read type
        int read_type_result = read_line(file_buffer, BUFF_SIZE, dest->type, NAME_TYPE_SIZE, stream);
        if (read_type_result != 0)
        {
            error = read_type_result;
            break;
        }

        int read_name_result = read_line(file_buffer, BUFF_SIZE, dest->name, NAME_TYPE_SIZE, stream);

        if (read_name_result != 0)
        {
            error = read_name_result;
            break;
        }

        char value_buffer[VALUE_SIZE] = { 0 };
        int read_value_result = read_line(file_buffer, BUFF_SIZE, value_buffer, VALUE_SIZE, stream);
        if (read_value_result != 0)
        {
            error = read_value_result;
            break;
        }

        if (0 == strcmp(find_name, dest->name))
        {
            if (1 != sscanf(value_buffer, "%d", &dest->value))
            {
                error = CANT_FORMAT_VALUE;
            }
            break;
        }
    }

    fclose(stream);

    return error;
}

You just need to call the function find_var_in_file like in main. I loop over all the lines of the file and search for the var name. If have formating error or not find the name of the var in the file return the error code.

jacob galam
  • 781
  • 9
  • 21
  • 2
    This program will generate several warnings: `return` with no value, in function returning non-void; format `%s` expects argument of type `char *`, but argument {3,4} has type `char (*)[5]`; unused variable `count`. Additionally: `&file_buffer` in the call the `fread` may work, but typically this would be written as `file_buffer`, as an array will already decay to a pointer-to-the-first-element when passed as a function argument. – Oka Sep 05 '21 at 18:51
  • 2
    *"Also, sscanf is very dangerous because of buffer overflow."* -- which you have the opportunity to address by using a [*maximum field width*](https://en.cppreference.com/w/c/io/fscanf) specifier to limit the amount of data read into your arrays (e.g., `"%4s"`). – Oka Sep 05 '21 at 18:54
  • 2
    Finally: you are attempting to read `1024` bytes from the file without checking either your return size from `fread`, or your conversion matches from `sscanf` for validity. – Oka Sep 05 '21 at 18:58
  • 1
    @Oka Thanks you for your feedback! I tried to address the warnings. Also What do you mean by: "format %s expects argument of type char *, but argument {3,4} has type char (*)[5]" Can you give me an example how I fix that in my code? – jacob galam Sep 05 '21 at 19:18
  • 1
    Slightly verbose: `object2->type` has the type `char [10]` (*array of 10 char*), which means `&object2->type` has the type `char (*)[10]` (*pointer to array of 10 char*). The `*scanf` specifier `"%s` (and `"%[]"`) expect a `char *` (*pointer to char*). When used as a function argument, type `char [N]` will naturally *decay* to `char *`. Thusly: `&object2->type` should be `object2->type`, and `&object2->name` should be `object2->name`. (Note that it currently works because [...reasons](https://stackoverflow.com/a/54807267/2505965), but is generally bad form). – Oka Sep 05 '21 at 19:28
  • I appreciate your answers but what I do not understand is how do I reach these stored values? Like for example I want to have int a =5; What I want is to store that value from structure into some int value. –  Sep 05 '21 at 19:38
  • @PPProgramer If I understand you right, you can loop over all your objects, if you have many variables in the file (loop every line and store in array or List or something) and compare your name to the name you want `if (strcmp(object2.name, "A") == 0) {int a = object.value} // a = 5 in the file`. If you ask for `reflection` C doesn't have it, when you named variable you can't change after you compiled. If you want I can update my code to do that and update to the new formatting – jacob galam Sep 05 '21 at 21:42
  • That would be helpfull. Thank You! –  Sep 06 '21 at 11:36
  • @PPProgramer I update the code. Now is supporting the new format and search the var in the file. Please upward and mark as answer if it is the answer – jacob galam Sep 06 '21 at 13:11
  • Thank you but i still dont have reputation to upvote –  Sep 06 '21 at 16:22
0

If the file you are trying to read is a text file (which it is in your case), then use fgets() to read its content. Also, if its content has a consistent format, then consider using sscanf() to do your parsing.

I don't understand why you are using a pointer to struct variable to save data. You can simply use a struct variable object and access its fields with .

Your code should look something like that:

#include <stdio.h>
#include <stdlib.h> // For exit()
#include <string.h> // for strlen()

struct variable {
    char type[10];
    char name[10];
    int value;
};

int main()
{
    FILE *file = fopen("input.txt", "r");
    if (!file) {
        fprintf(stderr, "Could not read file\n");
        return 1;
    }

    struct variable object2;
    char buffer[1024];

    while (fgets(buffer, 1024, file)) {
        if (sscanf(buffer, "%9s %9s %d", object2.type, object2.name, &object2.value) != 3) {
            fprintf(stderr, "Error parsing file\n");
            fclose(file);
            return 1;
        }

        printf("%s %s %d\n", object2.type, object2.name, object2.value);
    }

    fclose(file);
}

Now, if you want to store all the lines of your file into variables to use them later, then first you need to count the number of lines in your file (let's call it n) and second, allocate a dynamic array of size n.

Zakk
  • 1,935
  • 1
  • 6
  • 17
0
fscanf(file,"%s\n%s\n%d\n",object2->type,object2->name,&object2->value);
Blastfurnace
  • 18,411
  • 56
  • 55
  • 70
Rayoub
  • 1
  • 1