2016-05-22 37 views
0

最後の2日間でquestion to load structを依頼しましたが、私の構造体にアクセスする際に問題があります。 )。構造体のメンバーとしてchar **配列の構造体をロード/塗りつぶします。

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). 
} 

私の構造体への私のchar型の配列をロード中にseg_faultエラーを取得しています:私は私の質問/およびコードをこのように編集しました。 (つまり、この行:myinfo[i].cources_as_list = std_cource_list;

+0

'char ** mydata'、' char ** mydata'または 'char ** mydata;'または 'char ** mydata'の中から一番良いものを使用しますが、それらを混同しないでください。 'malloc()'の戻り値を常にチェックし、巨大な割り当てのような特殊な状況下でない限り、固定サイズを 'malloc()'しないでください。 –

+2

あなたはどこにでも 'myinfo'のためのメモリを割り当てません。 –

+0

@JoachimPileborg:私の構造体(myinfo)を割り当てようとしていますが、新しいC言語を使用しています。私はこのようにします** myinfo [i] .cources_as_list = malloc(sizeof(char **)); **。でも同じ問題ですが、あなたは私の構造体をmallocに導くことができますか?ありがとう。 –

答えて

0

構造体のメモリを割り当てる必要があります。

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

このタスクでは、グローバル変数は必要ないため、グローバル化しないでください。

+0

これは、正確に* one * 'std_info'構造体にのみメモリを割り当てます。 – alk

+0

私は今、自分の過ちを見ることができます。ありがとうございます... –

+0

この行を使用して、 'myinfo [i] .cources_as_list = ...'は 'i'が' 0'より大きいときに未定義の動作を呼び出します。 – alk

-1

myinfoの領域は割り当てられません。ローカル変数にすることをお勧めします。非常に特殊な場合を除いて、グローバル変数はほとんど必要ありません。

malloc()また、固定サイズの割り当てでは管理が簡単で、静的に配列を使用できる場合はより効率的です。

これはあなたが私がstrdup()を使用したことがないことがわかります

#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; 
} 

に興味を持っている何であるかもしれない、その理由は、私たちがコピーしたい文字列の常に知られているということで。

+0

あなたは私の構造体、myinfoをどのようにmallocできますか?ありがとう。 –

+0

私はあなたが 'malloc()'を全く必要としないと思います。それをポインタとして宣言して、必要なときにそのアドレスを渡してはいけません。 –

0

これは第一にmyinfoポインティングで、std_infoline_countオブジェクトを保持するためのメモリを割り当て

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

試してみてください。

関連する問題