2017-05-05 3 views
0

이 질문은 실제로 this topic에 가깝지만이 솔루션에서 제공하는 lisibility 및 포인터 설명을 선호합니다.문자열을 문자열 배열로 분할하면 동적으로 할당됩니다.

데이터 파일이 있는데 그 파일에서 매우 긴 배열을 가져옵니다. 이 문자열을 배열로 나눠서이 파일의 한 줄에 해당하는 문자열을 넣고 싶습니다.
솔루션을 보았지만 각 라인의 길이를 알지 못하기 때문에 제한된 배열을 사용합니다. 실제로 모든 것을 동적으로 할당해야하지만 strtok은 입력하지 않기 때문에 라인의 길이를 찾을 수 없습니다. 각 문자열의 끝 부분에 널 문자 \0이 있습니다.

int get_lines(char *file, char **lines) { 
    int nb_lines = 0; 
    char *token = strtok(file, "\n"); 
    for(int i = 0; token != NULL; i++) { 
     token = strtok(NULL, "\n"); 
     nb_lines = i; 
    } 
    nb_lines++; 

    lines = malloc((nb_lines + 1) * sizeof(char*)); 
    lines[nb_lines] = '\0'; 

    token = strtok(file, "\n"); 
    for(int i = 0; token != NULL; i++) { 
     token = strtok(NULL, "\n"); 
     int nb_char = 0; 
     for(int j = 0; token[j] != '\n'; j++) //This will cause SIGSEGV because strtok don't keep the '\n' at the end 
      nb_char = j; 
     nb_char++; 
     token[nb_char] = '\0'; //This cause SIGSEGV because token's allocation finish at [nb_char-1] 
     lines[i] = malloc(strlen(token) * sizeof(char)); //strlen cause SIGSEGV because I cannot place the '\0' at the end of token 
     printf("%s", token); //SIGSEGV because printf don't find the '\0' 
     lines[i] = token; 
    } 

    for(int i = 0; i < nb_lines; i++) { 
     printf("%s", lines[i]); //SIGSEGV 
    } 

    return nb_lines; 
} 

그래서 당신은 내가 뭘 원하는지의 생각 이상으로 볼 수 있으며 작동하지 않는 이유 : 내가 지금 가지고 무엇

이 두 가지 솔루션을하지만, 어느 작품이다. 아래에서

내가 만든 다른 시도를 볼 수 있지만 같은 지점에서 붙어 :

int count_subtrings(char* string, char* separator) { 
    int nb_lines = 0; 
    char *token = strtok(string, separator); 
    for(int i = 0; token != NULL; i++) { 
     token = strtok(NULL, separator); 
     nb_lines = i; 
    } 
    return nb_lines + 1; 
} 

char** split_string(char* string, char* separator) { 
    char **sub_strings = malloc((count_subtrings(string, separator) + 1) * sizeof(char*)); 
    for(int i = 0; string[i] != EOF; i++) { 
     //How to get the string[i] lenght to malloc them ? 
    } 
} 

내 파일이 매우 크고 라인도 할 수 있도록 내가를 malloc을하고 싶지 않아 (strlen(file) + 1) * sizeof(char)의 크기를 가진 다른 테이블은 각 행이 SIGSEGV가 아닐 것이고 나는 또한이 해결책이 상당히 더럽다는 것을 알게 될 것입니다. 만약 여러분들이 다른 생각을 가지고 있다면, 나는 정말로 행복 할 것입니다. 한 번만 원래 문자열을 전달할 수 있도록 첫째, strtok는 문자열을 수정합니다

+1

가능한 복제 (http://stackoverflow.com/questions/43779687/handle-memory-while-reading-long-lines-from-a -file-in-c) – Badda

+0

동적 연결 목록 종류의 데이터 구조를 사용할 수 있습니다. –

+0

realloc 체크 아웃 –

답변

0

strtok와 귀하의 접근 방법은 두 가지 단점이 있습니다 (영어 실수 죄송합니다, 나는 정말 좋은 아니에요). 둘째, 공백 라인은 건너 뜁니다. 왜냐하면 그것은 넬라가 단일 토큰 구분 기호로 뻗어 있기 때문입니다. (나는 당신이 염려하는 것이 무엇인지 모르겠습니다.)

줄 바꿈을 한 줄로 계산할 수 있습니다 . 당신의 라인 어레이를위한 메모리를 할당하고 개행 문자의 문자열을 분할 두 번째 패스합니다

char **splitlines(char *msg) 
{ 
    char **line; 
    char *prev = msg; 
    char *p = msg; 

    size_t count = 0; 
    size_t n; 

    while (*p) { 
     if (*p== '\n') count++; 
     p++; 
    } 

    line = malloc((count + 2) * sizeof(*line)); 
    if (line == NULL) return NULL; 

    p = msg; 
    n = 0; 
    while (*p) { 
     if (*p == '\n') { 
      line[n++] = prev; 
      *p = '\0'; 
      prev = p + 1; 
     } 

     p++; 
    } 

    if (*prev) line[n++] = prev; 
    line[n++] = NULL; 

    return line; 
} 

나는 줄 바꿈에 비해 두 개 더 라인 포인터를 할당 한 카운트 : 하나 경우에 대한 마지막 줄은 '아무튼 있음 t 줄 바꿈 문자로 끝내고 다른 하나는 끝에 NULL 마침표를 놓고 yourArray가 어디에서 끝나는 지 알 수 있습니다. (당신은 물론, size_t에 대한 포인터를 통해 실제 행 수를 반환 할 수 있습니다.)

+0

우선, 도와 주셔서 감사합니다. 알고리즘이 너무 깨끗합니다. 정말 좋습니다. 몇 가지 질문이 있는데 왜 배열을 통과하기 위해'size_t' 변수 만 사용합니까? "'size_t'에 대한 포인터를 통해 실제 줄 수를 반환한다는 것은 무엇을 의미합니까? 어떻게 작동합니까? '* p '가'0 '이면 두 번째'while (* p)'이 깨지지 않는 이유는 무엇입니까? 'line [n ++] = prev;'에서'line [n] = prev;'명령 뒤에'n'이 증가합니다. 그리고 malloc()의 실패는 모든 코드에서 정말 신경 써야 할 부분입니까? –

+0

(1)'size_t'는 부호없는 정수 유형입니다. 표준 라이브러리는'strlen'에 의해 반환 된 값과 같이 음수가 될 수없는 것들에 대해서도 이것을 사용합니다. 원하는 경우'int'를 사용할 수 있습니다. (2) 함수를'f (char * s, size_t * pn)'로 만든 다음 반환하기 전에'if (pn) * pn = n;'이라고 말하십시오. (나는 실수를했습니다. –

+0

(3)'line [n ++] = x'는 전형적인 C 관용구입니다. 'n'항목의 배열은 0에서'n - 1' 사이의 유효한 색인을 가지고 있음을 기억하십시오. 'n'항목은 유효한 범위 바로 뒤의 항목입니다. 배열에 추가 할 때 해당 필드에 할당하고 개수를 증가시킵니다. (4) 그렇습니다. 현재 코드에서 호출하는 함수는 반환 된 포인터가 null이 아닌지 확인해야합니다. 빠른 솔루션으로 할당이 실패하면 프로그램을 중단 할 수도 있습니다. –

0

다음과 같은 제안 코드 :

  1. 깔끔하게
  2. (힙 크기의 범위 내에서) 컴파일 아무튼
  3. 에코는 파일 행의 결과 배열로, 공백을 두 번 공백으로 표시하여 효과가 있음을 나타냅니다. untitled1.c 다음이 출력됩니다 : 단일 간격에 대해, 이제 코드라는 이름의 파일에 위의 코드를 감안할 때

    #include <stdio.h> // getline(), perror(), fopen(), fclose() 
    #include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free() 
    
    
    int main(void) 
    { 
        FILE *fp = fopen("untitled1.c", "r"); 
        if(!fp) 
        { 
         perror("fopen for reading untitled1.c failed"); 
         exit(EXIT_FAILURE); 
        } 
    
        // implied else, fopen successful 
    
        char **lines = NULL; 
        size_t availableLines = 0; 
        size_t usedLines = 0; 
    
        char *line = NULL; 
        size_t lineLen = 0; 
        while(-1 != getline(&line, &lineLen, fp)) 
        { 
         if(usedLines >= availableLines) 
         { 
          availableLines = (availableLines)? availableLines*2 : 1; 
          char **temp = realloc(lines, sizeof(char*) * availableLines); 
          if(!temp) 
          { 
           perror("realloc failed"); 
           free(lines); 
           fclose(fp); 
           exit(EXIT_FAILURE); 
          } 
    
          // implied else realloc successful 
    
          lines = temp; 
         } 
    
         lines[ usedLines ] = line; 
         usedLines++; 
         line = NULL; 
         lineLen = 0; 
        } 
    
        fclose(fp); 
    
        for(size_t i = 0; i<usedLines; i++) 
        { 
         puts(lines[i]); 
        } 
    
        free(lines); 
    } 
    

    printf()

puts()을 대체합니다.[C의 파일로부터 긴 라인을 읽는 동안 메모리 핸들]의

#include <stdio.h> // getline(), perror(), fopen(), fclose() 

#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free() 





int main(void) 

{ 

    FILE *fp = fopen("untitled1.c", "r"); 

    if(!fp) 

    { 

     perror("fopen for reading untitled1.c failed"); 

     exit(EXIT_FAILURE); 

    } 



    // implied else, fopen successful 



    char **lines = NULL; 

    size_t availableLines = 0; 

    size_t usedLines = 0; 



    char *line = NULL; 

    size_t lineLen = 0; 

    while(-1 != getline(&line, &lineLen, fp)) 

    { 

     if(usedLines >= availableLines) 

     { 

      availableLines = (availableLines)? availableLines*2 : 1; 

      char **temp = realloc(lines, sizeof(char*) * availableLines); 

      if(!temp) 

      { 

       perror("realloc failed"); 

       free(lines); 

       fclose(fp); 

       exit(EXIT_FAILURE); 

      } 



      // implied else realloc successful 



      lines = temp; 

     } 



     lines[ usedLines ] = line; 

     usedLines++; 

     line = NULL; 

     lineLen = 0; 

    } 



    fclose(fp); 



    for(size_t i = 0; i<usedLines; i++) 

    { 

     puts(lines[i]); 

    } 



    free(lines); 

}