简体   繁体   中英

Load/fill a struct with char** array as a struct member, c

In the last two days i have asked a question to load struct , but i have a problem to access my struct out side my loop(a loop to load my struct). i have edited my question/and code this way:

myfile.txt

Biology,chemistry,maths,music
Mechanics,IT,Geology,music,Astronomy
football,vollyball,baseball

main.c

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

#define path "myfile.txt"

typedef struct student_info 
{
    char **cources_as_list;
} std_info;

std_info *myinfo; //a global var that will conatain student info
int line_count = 0, cource_count = 0;

char** load_file() 
{
    char *line = NULL;
    size_t len = 0;
    FILE *fp;
    int indexq=0;
    fp = fopen(path, "r");
    if (fp == NULL) 
    {
        perror("FILE OPEN ERROR[IN load_file]: ");
        exit(1);
    }
    char **mydata = malloc (sizeof (char *) * 4);//aup to four elements
    while (getline(&line, &len, fp) != -1) 
    {
        strtok(line, "\n");
        mydata[indexq]= strdup(line);
        indexq++;
    }
    line_count = indexq;
   return mydata;
}

char **return_cource_list(char *cources_string) {
    char *token;
    char **cource_list = malloc(sizeof(char *) * 10);
    int index = 0;
    //course_string is delimited by ",": (eg. Biology,chemistry,maths,music). parse this and add to my char ** variable.
    token = strtok(cources_string, ",");
    while (token != NULL) 
    {
        cource_list[index] = strdup(token);
        token = strtok(NULL, ",");
        index++;
    }
    cource_count = index;
    return cource_list;
}
int main() 
{
    int i, j;
    char** mydata = load_file(); //returns lines as a list/char ** array from file
    for (i = 0; i < line_count; i++) //line_count is the number of elements/lines in "mydata"
    {
        printf("line_data: %s\n",mydata[i]);//i can see all my lines!
        char **std_cource_list = return_cource_list(mydata[i]);
        for (j = 0; j < cource_count; j++) 
        {
            printf("\tcourse[%d]: %s\n",j,std_cource_list[j]);//i have all my courses as a list from each line
        }
        //can i load my struct like this? or any option to load my struct?
        myinfo[i].cources_as_list = std_cource_list;
    }

    // i want to see my structure elements here, (nested for loop required).
}

Am getting seg_fault error while loading my char array to my struct. (ie: this line: myinfo[i].cources_as_list = std_cource_list; )

You need to allocate the memory for your struct.

std_info *myinfo = malloc(sizeof(std_info));

Also don't make it global, since there is really no need for global variables in this task.

Try

std_info * myinfo = malloc(line_count * sizeof *myinfo);

This allocates memory to hold line_count objects of std_info , with myinfo pointing to the 1st.

You never allocate space for myinfo and I would suggest making it a local variable. There is almost no need for global variables except in very specific cases.

Also, you are using malloc() almost only for fixed size allocations which would be easier to manage and more efficient if you do statically in the sense that you can use arrays for that.

This might be what you're interested in

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

struct student_info 
{
    char **courses;
    size_t size;
};

char **
load_file(const char *const path)
{
    char *line;
    FILE *file;
    char **data;
    size_t row;
    size_t length;
    size_t count;

    file = fopen(path, "r");
    if (file == NULL) 
    {
        perror("FILE OPEN ERROR[IN load_file]: ");
        return NULL; // Notify the caller that there was a problem
                     // but do not necessarily quit as you might
                     // retry with another path.
    }

    count = 0;
    for (int chr = fgetc(file) ; chr != EOF ; chr = fgetc(file))
        count += (chr == '\n') ? 1 : 0;
    rewind(file);

    data = malloc((count + 1) * sizeof(*data));
    if (data == NULL)
    {
        // Perhaps notify the error
        fclose(file);
        return NULL;
    }
    data[count] = NULL; // Use as end of array delimiter

    row = 0;
    line = NULL;
    length = 0;
    while ((length = getline(&line, &length, file)) != -1) 
    {
        // The last character is always `\n' so remove it
        data[row] = malloc(length);
        if (data == NULL)
        {
            fclose(file);
            for (size_t i = row ; i >= 0 ; --i)
            {
                free(data[i]);
                free(data);

                return NULL;
            }
        }
        data[row][length - 1] = '\0';
        memcpy(data[row], line, length - 1);

        ++row;
    }

    fclose(file);
    // You need to `free' this, read the documentation
    free(line);

    return data;
}

char **
extract_courses_as_list(const char *const input) 
{
    char **courses;
    size_t index;
    const char *tail;
    const char *head;
    size_t count;

    head = input;
    count = 0;
    /* Count the number of fields to allocate memory */
    while (head != NULL)
    {
        tail = strchr(head, ',');
        if (tail != NULL)
            head = tail + 1;
        else
            head = NULL;
        count += 1;
    }

    index = 0;
    /* Allocate memory for the list, and the sentinel */
    courses = malloc((count + 1) * sizeof(*courses));
    head = input;
    while (head != NULL)
    {
        ptrdiff_t length;
        /* find the next `,' in the input string */
        tail = strchr(head, ',');
        if (tail == NULL) /* if it's not there, it's the last one */
            tail = strchr(head, '\0');
        /* compute the number of characters of the field */
        length = (ptrdiff_t) (tail - head);
        /* allocate space to copy the string */         
        courses[index] = malloc(length + 1);
        if (courses == NULL) /* always be safe and check */
        {
            for (size_t i = index ; i >= 0 ; --i)
                free(courses[index]);
            free(courses);
            return NULL;
        }
        /* always remember to `null' terminate */
        courses[index][length] = '\0';
        /* finally, copy the string */
        memcpy(courses[index], head, length);
        /* check whehter it was the last field and
         * update the pointer to the next one accordingly             
         */
        if ((tail != NULL) && (*tail != '\0'))
            head = tail + 1;
        else
            head = NULL;
        /* Don't forget the fields counter */
        index++;
    }
    courses[count] = NULL;

    return courses;
}

void
concatenate_lists(struct student_info *info, char **source)
{
    char **temporary;
    size_t length;
    length = info->size;
    for (size_t i = 0 ; source[i] != NULL ; ++i)
        length++;
    temporary = realloc(info->courses, length * sizeof(*temporary));
    if (temporary == NULL)
        return;
    for (size_t i = 0 ; source[i] != NULL ; ++i)
        temporary[i + info->size] = strdup(source[i]);
    info->courses = temporary;
    info->size = length;
}


void
free_list(char **lines)
{
    if (lines == NULL)
        return;
    for (size_t i = 0 ; lines[i] != '\0' ; ++i)
        free(lines[i]);
    free(lines);
}

int 
main() 
{
    struct student_info info;
    char **lines;
    lines = load_file("data.tx");
    if (lines == NULL)
        return -1;
    info.courses = NULL;
    info.size = 0;
    for (size_t i = 0 ; lines[i] != NULL ; ++i)
    {
        char **courses;
        courses = extract_courses_as_list(lines[i]);
        if (courses == NULL)
            continue;
        concatenate_lists(&info, courses);
        free_list(courses);
    }

    for (size_t i = 0 ; i < info.size ; ++i)
    {
        fprintf(stderr, "%s\n", info.courses[i]);
        free(info.courses[i]);
    }
    free(info.courses);
    free_list(lines);

    return 0;
}

You will notice that I never used strdup() , the reason being that the length of the string that we want to copy is always known.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM