2017-01-14 31 views
0

関数の実装をコード化する必要がありますが、FILE *ではなくファイルのファイル記述子を使用する必要があります。私はmalloc()free()を使用することが許されているだけでなく、5つの機能が最大25行の長さになっています。 私はCの初心者ですが、私のコードはうまくいきませんが、私はプロジェクトを正しく行ったと思います。getline()implentationのコード化 - Valgrindエラー

私はそれを実行すると問題なく動作しますが、valgrindはファイルの長さとREAD_SIZE(ヘッダーに定義されているマクロ)に依存するx definetely lost x bytesを示しています。

valgrindの--leak-check=fullによると、私は関数でメモリリークを持っています。これは、malloc destです。私はしようとしましたが、どこで自由にすべきか/何か他のことをするべきではありません任意のヘルプまたはヒントに

#define SOF(x) sizeof(x) // Why in the comments 

int main(int ac, char **av) 
{ 
    int fd; 
    char *s; 

    UNUSED(ac); 
    if (!av[1]) 
    return 1; 
    fd = open(av[1], O_RDONLY); 
    while ((s = get_next_line(fd))) 
    { 
     printf("%s\n", s); 
     free(s); 
    } 
    close(fd); 
} 

ありがとう:あなたがテストしたい場合

char *get_next_line(const int fd) 
{ 
    static char *remaining = ""; 
    char   *buffer; 
    ssize_t  cread; 
    size_t  i; 

    i = 0; 
    if (remaining == NULL) 
    return (NULL); 
    if ((buffer = malloc(SOF(char) * READ_SIZE + 1)) == NULL || 
     (cread = read(fd, buffer, READ_SIZE)) < 0) 
     return (NULL); 
    buffer[cread] = 0; 
    remaining = str_realloc_cat(remaining, buffer); 
    while (remaining[i]) 
    { 
     if (remaining[i] == 10) 
     { 
      remaining[i] = 0; 
      buffer = str_create_cpy(remaining); 
      remaining = remaining + i + 1; 
      return (buffer); 
     } 
     i++; 
    } 
    return (check_eof(fd, buffer, remaining, cread)); 
} 

char *str_realloc_cat(char *rem, char *buf) 
{ 
    size_t i; 
    size_t dest_i; 
    char *dest; 

    i = (dest_i = 0); 
    if ((dest = malloc(SOF(char) * (str_len(rem) + str_len(buf) + 1))) == NULL) 
    return (NULL); 
    while (rem[i]) 
    { 
     dest[dest_i] = rem[i]; 
     dest_i++; 
     i++; 
    } 
    i = 0; 
    while (buf[i]) 
    { 
     dest[dest_i] = buf[i]; 
     dest_i++; 
     i++; 
    } 
    dest[dest_i] = 0; 
    free(buf); 
    return (dest); 
} 

char *check_eof(const int fd, char *buffer, char *remaining, ssize_t cread) 
{ 
    if (cread == 0) 
    return (NULL); 
    if (cread < READ_SIZE) 
    { 
     buffer = remaining; 
     remaining = NULL; 
     return (buffer); 
    } 
    return (get_next_line(fd)); 
} 

char *str_create_cpy(const char *src) 
{ 
    char *dest; 
    size_t i; 

    i = 0; 
    if ((dest = malloc(sizeof(char) * str_len(src) + 1)) == NULL) 
    return (NULL); 
    while (src[i]) 
    { 
     dest[i] = src[i]; 
     i++; 
    } 
    dest[i] = 0; 
    return (dest); 
} 

int str_len(const char *str) 
{ 
    size_t i; 

    i = 0; 
    while (str[i]) 
    i++; 
    return (i); 
} 

メインfuncton:

は、ここに以下の私のコードです。

+1

'のはsizeof(charは)'常に1で、汚染しませんそれとあなたのコード。 – DyZ

+3

'#define SOF(x)sizeof(x)'を使用する - 図示されていませんが、推測されていません - 少し無意味です。それは混乱の犠牲を払って、1通話につき3文字の入力を節約します。良いトレードオフではありません。 –

+0

こんにちは、両方のご意見ありがとうございます。私は 'sizeof(char)'が常に1であることを知っていますが、それは良い習慣だと思っていますので、決して忘れないようにしてください。そして、何とかcharが別のシステムで1バイト以上あるなら、しかし)。また、SOFは実際にはsizeofの定義です。それは醜いですが、1行につき80文字、関数ごとに25行しか使わなければならないので、私のコード全体を再度構造化することなく唯一の方法でした。 –

答えて

2

あなたのアルゴリズムは悪いです:

  1. あなたは、あなたが使用してマジックナンバーremaining[i] == 10
  2. を使用
  3. あなたの変数を再編成するための構造を使用していない
  4. 割り当てるメモリ内のバッファを保ちます再帰的にオーバーフローをスタックすることができますreturn get_next_line(fd)。決して気にしないで、私はあなたが尾を再帰的に持っていることをよく読んでいなかった。ちょうどそのコンパイルの最適化があることを確かめておく。
  5. スパゲッティコードがあります。
  6. など

あなたが最初にこの構造を使用優れたロジックを使用して関数全体を書き換える必要があります。

char *get_next_line_r(int fd, struct gnl_context *gnl_context); 

:あなたは、スレッドセーフバージョンを書くことができるものと

#define GNL_SIZE 4096 

struct gnl_context { 
    char buffer[GNL_SIZE]; // Your buffer don't need to be dynamic 
    size_t i; // this is your index that you must use to iterate in the buffer 
    size_t read; // this is what read return 
}; 

を元の関数で次のようにします。

char *get_next_line(int fd) { 
    static struct gnl_context gnl_context; 
    return get_next_line_r(fd, &gnl_context); 
} 

そして、ここでは例として、これは明らかに完璧ではないと私はあなたがこれを使用することができないことを知っているが、それはあなたを助ける必要があります。

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

#define GNL_SIZE 4096 

struct gnl_context { 
    char buffer[GNL_SIZE]; 
    size_t i; 
    size_t read; 
}; 

char *get_next_line_r(int fd, struct gnl_context *gnl_context); 
char *get_next_line(int fd); 

static char *cpy_buffer(struct gnl_context *gnl_context, size_t i, 
         size_t *size) { 
    char *str = malloc(i - gnl_context->i + 1); 
    if (str == NULL) { 
    return NULL; 
    } 
    memcpy(str, gnl_context->buffer + gnl_context->i, i - gnl_context->i); 

    *size = i - gnl_context->i; 
    str[*size] = '\0'; 
    gnl_context->i = i; 

    return str; 
} 

static char *cat_str_and_buffer(struct gnl_context *gnl_context, char *str, 
           size_t *size, size_t i) { 
    char *ret = malloc(*size + (i - gnl_context->i) + 1); 
    if (ret == NULL) { 
    return NULL; 
    } 
    memcpy(ret, str, *size); 
    memcpy(ret + *size, gnl_context->buffer + gnl_context->i, i - gnl_context->i); 

    *size += i - gnl_context->i; 
    ret[*size] = '\0'; 
    gnl_context->i = i; 

    return ret; 
} 

static char *read_buffer(struct gnl_context *gnl_context, char *str, 
         size_t *size) { 
    size_t i = gnl_context->i; 
    while (i < gnl_context->read && gnl_context->buffer[i] != '\n') { 
    i++; 
    } 
    return str == NULL ? cpy_buffer(gnl_context, i, size) 
        : cat_str_and_buffer(gnl_context, str, size, i); 
} 

char *get_next_line_r(int fd, struct gnl_context *gnl_context) { 
    char *str = NULL; 
    size_t size = 0; 
loop: 
    if (gnl_context->i == gnl_context->read) { 
    ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE); 
    if (ret <= 0) { 
     return str; 
    } 
    gnl_context->read = (size_t)ret; 
    gnl_context->i = 0; 
    } 

    char *tmp = read_buffer(gnl_context, str, &size); 
    if (tmp == NULL) { 
    return str; 
    } 
    free(str); 
    if (gnl_context->i != gnl_context->read) { 
    gnl_context->i++; 
    return tmp; 
    } 
    str = tmp; 
    goto loop; 
} 

char *get_next_line(int fd) { 
    static struct gnl_context gnl_context; 
    return get_next_line_r(fd, &gnl_context); 
} 

int main(void) { 
    char *str; 
    while ((str = get_next_line(0)) != NULL) { 
    printf("%s\n", str); 
    free(str); 
    } 
} 
+0

さて、あなたはそこに入れた努力と批評に本当に感謝していますが、私は自分のアルゴリズムを修正することをもっと心配しました。私は3ヶ月も経たないうちにC言語でコーディングしていますので、まだたくさんのことを学んでいると思います。私は本当にそれを感謝し、明日、または私はこのプロジェクトをやった後、それを行うより良い方法を理解するために深く見ていきます。 –

1

私はこのラインが心配です:

remaining = remaining + i + 1; 

remainingは、割り当てられたバッファへのポインタです。この行では、あなたはそれを破壊します、つまり、それ以上あなたはfree()できませんことを意味します。

+0

私のポインタを移動する唯一の方法はありませんか?前に 'i + 1'で始まるものすべてをコピーする機能は本当にありません。 –

+1

@ Greg01reこのテクニックの問題は、 'remaining'に割り当てられたメモリを解放できないことです。あなたはそれを解放するために元のポインタを保持する必要があります。 – Schwern

+0

さて、私はfree'dすることはできません残ったメモリがついていると思いますか? –