简体   繁体   English

使用char **数组作为结构成员c加载/填充结构

[英]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). 在过去的两天里,我问了一个加载struct问题 ,但是我在访问循环(加载我的struct的循环)之外的结构时遇到了问题。 i have edited my question/and code this way: 我以这种方式编辑了我的问题/和代码:

myfile.txt myfile.txt

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

main.c 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. 将我的char数组加载到struct时出现seg_fault错误。 (ie: this line: myinfo[i].cources_as_list = std_cource_list; ) (即此行: 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. 这将分配内存以容纳std_info line_count对象,其中myinfo指向第一个。

You never allocate space for myinfo and I would suggest making it a local variable. 您永远不会为myinfo分配空间,我建议将其设置为局部变量。 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. 另外,您几乎只将malloc()用于固定大小的分配,如果您静态地进行操作(可以使用数组),则它将更易于管理且效率更高。

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. 您会注意到,我从未使用过strdup() ,原因是我们要复制的字符串的长度 始终是已知的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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