2014-10-08 58 views
0

我是編程新手,所以我不太好。但是我一直在打破我所陷入的段錯誤。關於爲char數組分配大小的段錯誤

基本上我想要一個多線程可訪問字符存儲,我可以從多個線程寫入並從一個線程讀取。

現在,由於緩衝區將顯示在屏幕上,我不想通過互斥鎖來保護讀取方面,因爲該鎖會導致非常高的爭用。

我想到的是一個靜態雙緩衝區,在函數中我寫入一個緩衝區,然後一旦我調用讀取,寫入緩衝區將被清空到讀取緩衝區,並且它返回一個指向讀取緩衝區的指針。

這確保了我可以安全地使用單個線程讀取並使用多個線程進行寫入。

我還沒有實施清理或輸出緩衝區,因爲我無法使寫入工作正常。

下面是可編譯的代碼,我演示了我想要的內容,我已經註釋掉了互斥體。 爲單行分配空間後,我得到一個段錯誤。如果我更改我的緩衝區步長,它會在什麼行上更改段錯誤。

我希望有人能啓發我我做錯了什麼!

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

char **message(char *msg, char mode, unsigned int *e) { 
    //static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 

    static unsigned int errflag = 0; 

    static unsigned int in_ln = 0; //amount of lines in the in_buf 

    static unsigned int in_bufsize = 0; // current amount of lines the in_buf can hold 
    static unsigned int out_bufsize = 0; // current amountof lines the out_buf can hold 

    static const unsigned int bufsize_step = 2; // step size to increase the buffersizes 

    static char **in_buf; 
    static char **out_buf; 

    unsigned int strlength = 0; 
    unsigned int i = 0, h = 0, j = 0; 
    unsigned int lncount = 0; // count of the amount of lines in the input message 'msg' 

    // return once errflag is set previously 
    if (errflag != 0) { 
     *e = errflag; 
     return NULL; 
    } 
    // mutex to ensure thread safety 
    /* 
    if (pthread_mutex_lock(&mtx) != 0) { 
     errflag = 1; 
     return NULL; 
    } 
    */ 

    //write to in_buf 
    if (mode == 'w') { 

     strlength = strlen(msg) + 1; 
     printf("\n-----------new call---------\n"); 

     for (i=0; i<strlength; i++) { 
      if (msg[i] == '\n' || msg[i] == '\0') { 
       printf("found newline or \\n char at %u, with length %u, store at offset %u\n", i, i-h, lncount + in_ln); 
       // check if buffer has suffcient size to hold a new line 
       if (lncount + in_ln >= in_bufsize) { 
        // increase buffer by a step 
        printf("realloc buf. from %u to %u\n", in_bufsize, in_bufsize + bufsize_step); 
        in_bufsize += bufsize_step; 
        in_buf = realloc(in_buf, in_bufsize * sizeof(char *)); 
        if (in_buf == NULL) { 
         errflag = 3; 
         *e = errflag; 
         goto end; 
        } 
       } 
       // allocate memory for the new line 
       printf("alloc new line %u to %u\n", lncount + in_ln, (i - h + 1)); 
       in_buf[lncount + in_ln] = realloc(in_buf[lncount + in_ln] ,(i - h + 1) * sizeof(char)); 
       if (in_buf[lncount + in_ln] == NULL) { 
        errflag = 4; 
        *e = errflag; 
        goto end; 
       } 

       // put the line into the buffer 
       for (j=0; h+j<i; j++) { 
        printf("%c", msg[h+j]); 
        in_buf[lncount + in_ln][j] = msg[h+j]; 
       } 
       printf("\n"); 
       in_buf[lncount + in_ln][j] = '\0'; 

       printf("string %u is %s\n", lncount + in_ln, in_buf[lncount + in_ln]); 
       h = i + 1; 
       lncount++; 
      } 
     } 

     in_ln += lncount; 

    // append in_buf to out_buf, clean in_buf 
    } else if (mode == 'r') { 
     printf("realloc out_buf to %u\n", out_bufsize + in_ln); 
     out_buf = realloc(out_buf, (out_bufsize + in_ln) * sizeof(char *)); 
     if (out_buf == NULL) { 
      errflag = 4; 
      *e = errflag; 
      goto end; 
     } 

     printf("copying pointers...\n"); 
     for (i=0; i<in_ln; i++) { 
      out_buf[i + out_bufsize] = in_buf[i]; 
      printf("copying %u. %s -> %u. %s\n", i + out_bufsize, out_buf[i + out_bufsize], i, in_buf[i]); 
      in_buf[i] = NULL; 
     } 

     out_bufsize = out_bufsize + in_ln; 
     in_ln = 0; 
    // cleanup 
    } else if (mode == 'c') { 
     lncount = 0; 
    } 

    end: 
    /* 
    if (pthread_mutex_unlock(&mtx) != 0) { 
     errflag = 1; 
     return buf; 
    } 
    */ 

    printf("in_buf: size %u\n", in_ln); 
    for (i=0; i<in_ln; i++) { 
     printf("%u. %s\n", i, in_buf[i]); 
    } 

    printf("out_buf: size %u\n", out_bufsize); 
    for (i=0; i<out_bufsize; i++) { 
     printf("%u. %s\n", i, out_buf[i]); 
    } 
    return out_buf; 
} 


int main() { 
    unsigned int error; 
    message("test test\n", 'w', &error); 
    message(NULL, 'r', &error); 
    message("test test2", 'w', &error); 
    message("test test3", 'w', &error); 
    message("test test4", 'w', &error); 
    message(NULL, 'r', &error); 
    message("test test5", 'w', &error); 
    message("test test6", 'w', &error); 
    message(NULL, 'r', &error); 
    message("test test7", 'w', &error); 
    message("test test8", 'w', &error); 
    message(NULL, 'r', &error); 
    message("test test9", 'w', &error); 
    message("test test10", 'w', &error); 
    message("test test11", 'w', &error); 
    message("test test12", 'w', &error); 
    message("test test13", 'w', &error); 
    message("test test14", 'w', &error); 

    message("lndsdss1\nln2\nln3\nln4\nln5\nln6\nln7\nln8\nln9\nln10\nln11\nln12\nln13\nln14\nln15\nln16\nln17\n", 'w', &error); 

    exit(0); 
} 
+2

您剛剛爲訪問'in_buf [lncount + in_ln]'而騰出空間的指針是** not ** 0-initialized。因此,'realloc(in_buf [lncount + in_ln],(i - h + 1)* sizeof(char));'會嘗試將所述指針用作事先分配點而不是退回到類似malloc的行爲模式,這將反過來調用*未定義的行爲*。對於將新擴展區域設置爲NULL值的if(in_buf == NULL),'else'條件可能會有很大幫助。 – WhozCraig 2014-10-08 08:00:46

+0

我看到,將realloc更改爲malloc也適用。我想知道這是爲什麼。你說這是因爲它不是0初始化的。你能詳細說明嗎? – 2014-10-08 08:34:54

+0

您可能想了解C如何通過使用以'0'結尾的'char'數組來模擬非C數據類型* string *。 – alk 2014-10-08 11:19:36

回答

-1

添加到WhozCraig的評論。您試圖將in_buf用作指向指針的指針數組,而in_buf是一個靜態變量。因此,in_buf被初始化爲NULL(0)。

如果您閱讀realloc的定義,如果傳遞的存儲器地址爲0,則它​​的行爲將類似於malloc

因此,現在你有一個已分配內存的指針數組,它的第一個元素也指向相同的地址,因爲in_bufin_buf[0]本質上是相同的地址。

因此,in_buf[0]指向一個有效的分配的存儲器位置,但是in_buf[1]in_buf[n-1]被保持垃圾值作爲malloc不內容設置爲0,與釋放calloc。當你超出in_buf[0]in_buf[1]時,它包含無效的內存地址,並且當realloc嘗試從該地址讀取時,會發生段錯誤。

+0

'in_buf'是靜態的,不是自動的。 – 2014-10-08 09:15:10

+0

@AntonSavin感謝您指出,將更新。 – 2014-10-08 09:16:28

+0

我明白了,如果我只是在buf [n]而不是realloc中使用'malloc',我的問題就解決了嗎? – 2014-10-08 09:21:26