2010-07-13 6 views
1

그래서 줄 단위로 텍스트 파일을 읽고 각 줄을 char 배열로 저장하려고합니다.strncpy 문자 배열에 줄 단위로 파일 복사

루프의 인쇄물에서 라인 당 줄 수와 문자 수를 올바르게 계산할 수 있지만 strncpy과 관련된 문제가 있습니다. 데이터 배열을 인쇄하려고하면 2 개의 이상한 문자 만 표시됩니다. 나는 strncpy으로 일한 적이 없으므로 내 문제가 null-termination과 관련이 있다고 느낍니다.

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

int main(int argc, char* argv[]) 
{ 
    FILE *f = fopen("/home/tgarvin/yes", "rb"); 
    fseek(f, 0, SEEK_END); 
    long pos = ftell(f); 
    fseek(f, 0, SEEK_SET); 
    char *bytes = malloc(pos); fread(bytes, pos, 1, f); 
    int i = 0; 
    int counter = 0; 
    char* data[counter]; 
    int length; 
    int len=strlen(data); 
    int start = 0; 
    int end = 0; 

    for(; i<pos; i++) 
    { 
     if(*(bytes+i)=='\n'){ 
      end = i; 
      length=end-start; 
      data[counter]=(char*)malloc(sizeof(char)*(length)+1); 
      strncpy(data[counter], bytes+start, length); 
      printf("%d\n", counter); 
      printf("%d\n", length); 
      start=end+1; 
      counter=counter+1; 
     } 
    } 
    printf("%s\n", data); 
    return 0; 
} 
+1

텍스트 파일의 형식은 무엇입니까? ASCII 또는 유니 코드 (UTF-8 또는 UTF-16)입니까? 또한 코드로 표시하고 더 읽기 쉽도록 코드를 다시 포맷 할 수 있습니까? 예를 들어 명령문 당 한 줄 씩. 감사합니다. – ChrisBD

+1

코드를 다시 포맷했지만 for 문은 여러 가지 편집 과정에서 어떻게 든 훼손되었습니다. 이 코드가 실제로 사용중인 코드인지 확인하십시오. –

+0

나는 당신의 문제에 대한 해결책이 무엇인지 모르겠다. 비슷한 문제가있다. 그러나 나는 약간의 팁을 줄 것이라고 생각했다. 메모리를 직접 mallocing하는 대신 strdup를 사용할 수 있어야한다. strncopy. strdup는 malloc을 사용하여 메모리를 할당하고 복사 프로세스를 처리합니다. 단 한 줄을 저장하지만, 나는 내장 된 기능에 대한 큰 팬이다. – Chris

답변

2

"data []"배열은 크기가 0 인 문자에 대한 포인터 배열로 선언됩니다. 포인터를 할당 할 때 공백이 없습니다. 이로 인해 문제가 발생할 수 있습니다.

가장 간단한 해결 방법은 배열 수를 결정하여 줄 수를 확인한 다음 "char ** data = malloc (number_of_lines * sizeof (char *))"와 같은 작업을 수행하는 것입니다. 그런 다음 "데이터 [카운터]"할당을 수행하면됩니다.

strncpy()가 문제입니다. 최대 바이트 수를 복사하는 경우 '\ 0'은 문자열을 종료하지 않습니다. strncpy()를 추가 한 후 "data [counter] [length] = '\ 0';"

끝에있는 printf()가 잘못되었습니다. 모든 행을 인쇄하려면 "for (i = 0; i < counter; i ++) printf ("% s \ n ", data [counter]);"

+1

'memcpy'를 사용할 수도 있습니다. 왜냐하면 그는 항상 정확히'length' 문자를 복사하기 때문입니다. –

+0

그는 길이 +1의 메모리를 할당했습니다 –

+0

바로, 'NUL'에 +1이 필요합니다. –

1

% s 형식 지정자로 데이터를 인쇄하려고하는데 데이터가 char에 대한 포인터 배열입니다.

이제 포기 크기의 문자열을 복사에 대해 이야기

:

는 지금까지 내가 그것을 좋아, 난 당신이 실 거예요 대신 strncpy에서 strncpy()와 같은

size_t strlcpy(char *dst, const char *src, size_t siz); 

의) strlcpy를 (사용하는 것이 좋습니다 것입니다 문자열을 NULL로 끝내십시오. strlcpy()가이 문제를 해결합니다.

strlcpy로 복사 된 문자열은 항상 NULL로 종료됩니다.

1

변수 data[counter]에 적절한 메모리를 할당하십시오. 귀하의 경우에는 카운터가 0으로 설정됩니다. 따라서 데이터 [1] 등에 액세스하려고하면 세그먼트 화 오류가 발생합니다.

[counter]와 같은 변수를 선언하는 것은 좋지 않습니다. 프로그램의 후속 흐름에서 카운터가 변경 되더라도 배열 데이터에 메모리를 할당하는 것은 유용하지 않습니다. 따라서 위에서 설명한 것처럼 이중 문자 포인터를 사용하십시오.

기존 루프를 사용하여 먼저 줄 수를 찾을 수 있습니다.

마지막 printf가 잘못되었습니다. 첫 번째 줄 만 인쇄합니다. 위의 문제를 해결 한 후에 루프를 반복합니다. 나쁜 주주의

2

여러 경우, 가장 적절한 하나 개의 존재가 :

int counter = 0; 
char* data[counter]; 

당신은 제로 요소와 가변 길이 배열로 data 선언했습니다. 그들의 이름에도 불구하고 VLA는 진정으로 가변적이지 않습니다. 배열을 할당 한 후에는 배열의 길이를 변경할 수 없습니다.당신이 정의되지 않은 동작을 호출하고, 그래서 그래서 당신은,

data[counter]=(char*)malloc(sizeof(char)*(length)+1); 
strncpy(data[counter], bytes+start, length); 

data[counter] 소유하지 않은 메모리를 참조하는 라인

을 실행할 때.

미리 파일에서 몇 줄을 읽었는지 모르기 때문에 동적으로 확장 할 수있는 구조를 만들어야합니다. 다음은 예입니다 :

size_t dataLength = SOME_INITIAL_SIZE_GREATER_THAN_0; 

당신은 배열을 할당합니다 :

/** 
* Initial allocation of data array (array of pointer to char) 
*/ 
char **dataAlloc(size_t initialSize) 
{ 
    char **data= malloc(sizeof *data * initialSize); 
    return data; 
} 

/** 
    * Extend data array; each extension doubles the length 
    * of the array. If the extension succeeds, the function 
    * will return 1; if not, the function returns 0, and the 
    * values of data and length are unchanged. 
    */ 
int dataExtend(char ***data, size_t *length) 
{ 
    int r = 0; 
    char **tmp = realloc(*data, sizeof *tmp * 2 * *length); 
    if (tmp) 
    { 
    *length= 2 * *length; 
    *data = tmp; 
    r = 1; 
    } 
    return r; 
} 

그런 다음 메인 프로그램에서, 당신은 선언 할 data 크기를 추적 할 수있는 별도의 변수로

char **data; 

로 예 :

data = dataAlloc(dataLength); 
처음에는

입니다. 그런 다음 루프에서, 당신은 그들이과 같이, 동일한 비교할 때 배열을 현재의 배열 크기에 대한 귀하의 카운터를 비교하고 확장 할 것 :

if (counter == dataLength) 
{ 
    if (!dataExtend(&data, &dataLength)) 
    { 
    /* Could not extend data array; treat as a fatal error */ 
    fprintf(stderr, "Could not extend data array; exiting\n"); 
    exit(EXIT_FAILURE); 
    } 
} 
data[counter] = malloc(sizeof *data[counter] * length + 1); 
if (data[counter]) 
{ 
    strncpy(data[counter], bytes+start, length); 
    data[counter][length] = 0; // add the 0 terminator 
} 
else 
{ 
    /* malloc failed; treat as a fatal error */ 
    fprintf(stderr, "Could not allocate memory for string; exiting\n"); 
    exit(EXIT_FAILURE); 
} 
counter++; 
1

변경

int counter = 0; 
char* data[counter]; 
... 
int len=strlen(data); 
... 
for(; i<pos; i++) 
... 
     strncpy(data[counter], bytes+start, length); 
... 

int counter = 0; 
#define MAX_DATA_LINES 1024 
char* data[MAX_DATA_LINES]; //1 
... 
for(; i<pos && counter < MAX_DATA_LINES ; i++) //2 
... 
     strncpy(data[counter], bytes+start, length); 
... 

// 1 : 라인에 대한 포인터 (예 : data [0] - data [MAX_DATA_LINES])에 유효한 메모리 저장 공간을 준비합니다. 이렇게하지 않으면 '세분화 오류'오류가 발생할 수 있습니다. 그렇지 않으면 운이 좋습니다.

// 2 : 파일의 총 줄 수가 < MAX_DATA_LINES인지 확인하십시오. 라인 데이터 [> MAX_DATA_LINES]에 대한 포인터의 메모리 저장 공간이 더 이상 유효하지 않으므로 '세그먼트 오류'오류가 발생하지 않습니다.

0

바이트 배열에서 보조 배열로 모든 문자열의 내용을 복사 할 필요가 없으므로 이것이 더 빠른 구현이라고 생각합니다. 당신은 물론 '\ n'문자를 잃을 것입니다.

또한 줄 바꿈 문자로 끝나지 않고 pos가 바이트 []에 사용되는 배열 색인으로 정의되고 길이가 길어야하는 파일도 고려합니다.

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

#define DEFAULT_LINE_ARRAY_DIM 100 

int main(int argc, char* argv[]) 
{ 
    FILE *f = fopen("test.c", "rb"); 
    fseek(f, 0, SEEK_END); 
    long pos = ftell(f); 
    fseek(f, 0, SEEK_SET); 
    char *bytes = malloc(pos+1); /* include an extra byte incase file isn't '\n' terminated */ 
    fread(bytes, pos, 1, f); 
    if (bytes[pos-1]!='\n') 
    { 
     bytes[pos++] = '\n'; 
    } 
    long i; 
    long length = 0; 
    int counter = 0; 
    size_t size=DEFAULT_LINE_ARRAY_DIM; 
    char** data=malloc(size*sizeof(char*)); 
    data[0]=bytes; 

    for(i=0; i<pos; i++) 
    { 
     if (bytes[i]=='\n') { 
      bytes[i]='\0'; 
      counter++; 
      if (counter>=size) { 
       size+=DEFAULT_LINE_ARRAY_DIM; 
       data=realloc(data,size*sizeof(char*)); 
       if (data==NULL) { 
        fprintf(stderr,"Couldn't allocate enough memory!\n"); 
        exit(1); 
       } 
      } 
      data[counter]=&bytes[i+1]; 
      length = data[counter] - data[counter - 1] - 1; 
      printf("%d\n", counter); 
      printf("%ld\n", length); 
     } 
    } 

    for (i=0;i<counter;i++) 
     printf("%s\n", data[i]); 

    return 0; 
}