2010-07-13 39 views
1

所以我試圖逐行閱讀一個文本文件並將每行保存到一個char數組中。用strncpy將文件一行一行地拷貝到char數組中

從我在循環中的打印輸出中,我可以告訴它正在計數行和每行正確的字符數,但我遇到了與strncpy有關的問題。當我嘗試打印數據數組時,它只顯示2個奇怪的字符。我從來沒有與strncpy合作,所以我覺得我的問題可能與空終止有關。

#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還是Unicode(UTF-8或UTF-16)? 您是否還可以重新格式化代碼,使其顯示爲代碼並更具可讀性 - 例如,每條語句一行。 謝謝。 – ChrisBD 2010-07-13 15:46:47

+1

我對代碼進行了重新格式化,但for語句在各種編輯中以某種方式被肢解;請檢查這是否是您正在使用的代碼。 – 2010-07-13 15:52:33

+0

我不確定你的問題的解決方案是什麼,因爲我有類似的問題,但我想我會給一個小建議:你應該能夠使用strdup而不是自己mallocing內存,然後使用strncopy。 strdup將使用malloc來分配內存並處理複製過程。只爲你節省一條線,但我是內置函數的忠實粉絲。 – Chris 2013-10-13 00:27:04

回答

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'字符。 – 2010-07-13 16:13:07

+0

他已經爲內存分配了長度+1 – 2010-07-13 16:29:12

+0

對,'NUL'需要+ 1。 – 2010-07-13 16:32:57

1

您試圖使用格式說明符%s打印數據,而您的數據是指向char的指針數組。

現在談論複製一個字符串給大小:

至於我喜歡它,我會建議你使用 是strlcpy()而不是函數strncpy()

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

爲函數strncpy不會用NULL終止字符串, strlcpy()解決了這個問題。

由strlcpy複製的字符串始終爲NULL終止。

1

爲變量​​分配適當的內存。在你的情況下,計數器設置爲0.因此,如果嘗試訪問數據[1]等,它將會出現分段錯誤。

聲明像data [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); 

​​指的是你沒有自己的內存,所以你調用未定義的行爲。

由於您不知道您事先從文件中讀取了多少行,因此需要創建一個可以動態擴展的結構。這裏有一個例子:

/** 
* 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; 

有獨立的變量來跟蹤大小:

size_t dataLength = SOME_INITIAL_SIZE_GREATER_THAN_0; 

你會分配陣列as

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:爲指向行的指針(例如數據[0]到數據[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; 
}