Automatically scan and resize buffer in C












1














I have a simple function that reads character by character from stdin, while resizing the buffer whenever needed. The implementation will only allow 256 characters to be read, but that can easily be modified. Are there an obvious problems with this function? ie. it relies on undefined behaviour. And how can performance be improved?



void scan(char **buffer) {
char *newBuffer;
unsigned char i = 0;
unsigned char size = 1;
*buffer = malloc(16);
(*buffer)[0] = 0;
while (1) {
(*buffer)[i] = getchar();
if ((*buffer)[i] == 'n') {
(*buffer)[i] = 0;
return;
}
if (i >= (size * 16)) {
size++;
newBuffer = realloc(*buffer, size * 16);
*buffer = newBuffer;
}
i++;
}
}









share|improve this question






















  • It seems that (if your UCHAR_MAX is 255) this implementation will support reading of 4080 characters, not 256.
    – Toby Speight
    Nov 13 '18 at 8:32
















1














I have a simple function that reads character by character from stdin, while resizing the buffer whenever needed. The implementation will only allow 256 characters to be read, but that can easily be modified. Are there an obvious problems with this function? ie. it relies on undefined behaviour. And how can performance be improved?



void scan(char **buffer) {
char *newBuffer;
unsigned char i = 0;
unsigned char size = 1;
*buffer = malloc(16);
(*buffer)[0] = 0;
while (1) {
(*buffer)[i] = getchar();
if ((*buffer)[i] == 'n') {
(*buffer)[i] = 0;
return;
}
if (i >= (size * 16)) {
size++;
newBuffer = realloc(*buffer, size * 16);
*buffer = newBuffer;
}
i++;
}
}









share|improve this question






















  • It seems that (if your UCHAR_MAX is 255) this implementation will support reading of 4080 characters, not 256.
    – Toby Speight
    Nov 13 '18 at 8:32














1












1








1







I have a simple function that reads character by character from stdin, while resizing the buffer whenever needed. The implementation will only allow 256 characters to be read, but that can easily be modified. Are there an obvious problems with this function? ie. it relies on undefined behaviour. And how can performance be improved?



void scan(char **buffer) {
char *newBuffer;
unsigned char i = 0;
unsigned char size = 1;
*buffer = malloc(16);
(*buffer)[0] = 0;
while (1) {
(*buffer)[i] = getchar();
if ((*buffer)[i] == 'n') {
(*buffer)[i] = 0;
return;
}
if (i >= (size * 16)) {
size++;
newBuffer = realloc(*buffer, size * 16);
*buffer = newBuffer;
}
i++;
}
}









share|improve this question













I have a simple function that reads character by character from stdin, while resizing the buffer whenever needed. The implementation will only allow 256 characters to be read, but that can easily be modified. Are there an obvious problems with this function? ie. it relies on undefined behaviour. And how can performance be improved?



void scan(char **buffer) {
char *newBuffer;
unsigned char i = 0;
unsigned char size = 1;
*buffer = malloc(16);
(*buffer)[0] = 0;
while (1) {
(*buffer)[i] = getchar();
if ((*buffer)[i] == 'n') {
(*buffer)[i] = 0;
return;
}
if (i >= (size * 16)) {
size++;
newBuffer = realloc(*buffer, size * 16);
*buffer = newBuffer;
}
i++;
}
}






beginner c






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 12 '18 at 22:20









wispi

404




404












  • It seems that (if your UCHAR_MAX is 255) this implementation will support reading of 4080 characters, not 256.
    – Toby Speight
    Nov 13 '18 at 8:32


















  • It seems that (if your UCHAR_MAX is 255) this implementation will support reading of 4080 characters, not 256.
    – Toby Speight
    Nov 13 '18 at 8:32
















It seems that (if your UCHAR_MAX is 255) this implementation will support reading of 4080 characters, not 256.
– Toby Speight
Nov 13 '18 at 8:32




It seems that (if your UCHAR_MAX is 255) this implementation will support reading of 4080 characters, not 256.
– Toby Speight
Nov 13 '18 at 8:32










2 Answers
2






active

oldest

votes


















2














Missing includes



I think you need to include <stdio.h> and <stdlib.h> for successful compilation.



Always check that allocations succeed



Look at




*buffer = malloc(16);
(*buffer)[0] = 0;



If malloc() returns a null pointer, then the assignment to its first element is undefined behaviour. Your program could crash, destroy your system, or (if you're unlucky) appear to work.



Always check that input succeeds



If getchar() returns EOF, we should stop reading. Note that by storing the result in a char, we lose the ability to distinguish EOF from valid input.



Avoid output-only parameters



Why do we return void, and instead write our result to a supplied pointer argument? I could understand accepting an argument if we were to re-use a buffer passed in, but we just discard it. I'd write this as



/* caller must release allocated memory with free() */
char *scan(void)


Be careful of overflow



If an input line reaches 255*16 = 4080 characters, size++ will overflow to zero. Then our realloc() acts as free(), and we find ourselves accessing memory out of bounds. I recommend using size_t for the length of allocated memory - allocation will fail before we reach the limits of size_t.



Consider increasing the allocation increment



This code reallocates every 16 chars. This makes for a lot of allocations for really long lines. One technique to avoid that, without hugely over-allocation for short lines, is to increase the increment as the buffer gets larger. So instead of always increasing by 16, we might double the buffer size instead, or perhaps double it and add 32. There are various strategies that can be used, with different performance implications (though the differences are likely small compared to the overhead of reading input at all).





Improved version



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

/* Read a line from standard input stream.

Returns a buffer that must be released with free(),
or a null pointer if none could be allocated.

The result will end in a newline character if a
full line was successfully read.
*/
char *scan(void)
{
size_t capacity = 16;
char *buffer = malloc(capacity);
if (!buffer) {
return NULL;
}
size_t i = 0;

int c; /* current input character */
while ((c = getchar()) != EOF) {
if (i + 2 > capacity) {
/* ensure space for c and terminating NUL */
capacity *= 2;
char *newbuf = realloc(buffer, capacity);
if (!newbuf) {
/* allocation failed - undo the read, terminate string, and return */
ungetc(c, stdin);
buffer[i] = '';
return buffer;
}

buffer = newbuf;
}

/* We have enough space; now store it */
buffer[i++] = (char)c;
if (c == 'n') {
break;
}
}

if (i == 0) {
/* we didn't read anything */
free(buffer);
return NULL;
}

buffer[i] = '';
return buffer;
}


Demo



#include <string.h>
int main(void)
{
char *s;
while ((s = scan())) {
printf("%04zu %sn", strlen(s), s);
free(s);
}
}





share|improve this answer





















  • re: scan(void). Corner case: when a input error occurs, the code will, if some data was read prior, not return indication of a error. To cope, suggest before if (i == 0) { add if (c == EOF && !feof(stdin)) { i = 0; }.
    – chux
    Nov 13 '18 at 20:44










  • Like the ungetc(c, stdin); part on allocation failure - have to remember that good detail.
    – chux
    Nov 13 '18 at 20:45










  • When will getchar() return an EOF? I'm still new to C and I thought that it will simply wait for an input?
    – wispi
    Nov 13 '18 at 22:27










  • @chux, not sure I understand your first comment - if there's a failure after some input was read, we'll return what we can (which won't end in a newline, so distinguishable from 'good' input). A subsequent call will return NULL. Does the function comment need to be clearer, perhaps?
    – Toby Speight
    Nov 14 '18 at 8:27










  • @wispi - getchar() will return EOF at the end of the input stream, or when there's any failure when reading. The most likely causes of failures are OS-dependent, so you should consult the manual pages on your own system to increase your understanding.
    – Toby Speight
    Nov 14 '18 at 8:32



















1
















  • realloc may fail. In that case, *buffer = newBuffer; without checking would result in a memory leak. Consider



        if (newBuffer) {
    *buffer = newBuffer;
    } else {
    handle_error_as_appropriate;
    }


  • Along the lines of the previous bullet, don't throw away valuable information you already obtained (in your case, the input length). Rather than being void, consider returning something useful. The standard Unix convention suggests returning a length of an input (or -1 on error).


  • The function presumes that the stream is infinite. It does not account for EOF of input errors.



  • I do not endorse meddling with input. You never know whether the newline character is significant or not. Refrain from



        if ((*buffer)[i] == 'n') {
    (*buffer)[i] = 0;


    Prefer



            (*buffer)[i + 1] = 0;


  • size *= 16 seems rather aggressive. Usual factor is 2.







share|improve this answer























    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207513%2fautomatically-scan-and-resize-buffer-in-c%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    Missing includes



    I think you need to include <stdio.h> and <stdlib.h> for successful compilation.



    Always check that allocations succeed



    Look at




    *buffer = malloc(16);
    (*buffer)[0] = 0;



    If malloc() returns a null pointer, then the assignment to its first element is undefined behaviour. Your program could crash, destroy your system, or (if you're unlucky) appear to work.



    Always check that input succeeds



    If getchar() returns EOF, we should stop reading. Note that by storing the result in a char, we lose the ability to distinguish EOF from valid input.



    Avoid output-only parameters



    Why do we return void, and instead write our result to a supplied pointer argument? I could understand accepting an argument if we were to re-use a buffer passed in, but we just discard it. I'd write this as



    /* caller must release allocated memory with free() */
    char *scan(void)


    Be careful of overflow



    If an input line reaches 255*16 = 4080 characters, size++ will overflow to zero. Then our realloc() acts as free(), and we find ourselves accessing memory out of bounds. I recommend using size_t for the length of allocated memory - allocation will fail before we reach the limits of size_t.



    Consider increasing the allocation increment



    This code reallocates every 16 chars. This makes for a lot of allocations for really long lines. One technique to avoid that, without hugely over-allocation for short lines, is to increase the increment as the buffer gets larger. So instead of always increasing by 16, we might double the buffer size instead, or perhaps double it and add 32. There are various strategies that can be used, with different performance implications (though the differences are likely small compared to the overhead of reading input at all).





    Improved version



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

    /* Read a line from standard input stream.

    Returns a buffer that must be released with free(),
    or a null pointer if none could be allocated.

    The result will end in a newline character if a
    full line was successfully read.
    */
    char *scan(void)
    {
    size_t capacity = 16;
    char *buffer = malloc(capacity);
    if (!buffer) {
    return NULL;
    }
    size_t i = 0;

    int c; /* current input character */
    while ((c = getchar()) != EOF) {
    if (i + 2 > capacity) {
    /* ensure space for c and terminating NUL */
    capacity *= 2;
    char *newbuf = realloc(buffer, capacity);
    if (!newbuf) {
    /* allocation failed - undo the read, terminate string, and return */
    ungetc(c, stdin);
    buffer[i] = '';
    return buffer;
    }

    buffer = newbuf;
    }

    /* We have enough space; now store it */
    buffer[i++] = (char)c;
    if (c == 'n') {
    break;
    }
    }

    if (i == 0) {
    /* we didn't read anything */
    free(buffer);
    return NULL;
    }

    buffer[i] = '';
    return buffer;
    }


    Demo



    #include <string.h>
    int main(void)
    {
    char *s;
    while ((s = scan())) {
    printf("%04zu %sn", strlen(s), s);
    free(s);
    }
    }





    share|improve this answer





















    • re: scan(void). Corner case: when a input error occurs, the code will, if some data was read prior, not return indication of a error. To cope, suggest before if (i == 0) { add if (c == EOF && !feof(stdin)) { i = 0; }.
      – chux
      Nov 13 '18 at 20:44










    • Like the ungetc(c, stdin); part on allocation failure - have to remember that good detail.
      – chux
      Nov 13 '18 at 20:45










    • When will getchar() return an EOF? I'm still new to C and I thought that it will simply wait for an input?
      – wispi
      Nov 13 '18 at 22:27










    • @chux, not sure I understand your first comment - if there's a failure after some input was read, we'll return what we can (which won't end in a newline, so distinguishable from 'good' input). A subsequent call will return NULL. Does the function comment need to be clearer, perhaps?
      – Toby Speight
      Nov 14 '18 at 8:27










    • @wispi - getchar() will return EOF at the end of the input stream, or when there's any failure when reading. The most likely causes of failures are OS-dependent, so you should consult the manual pages on your own system to increase your understanding.
      – Toby Speight
      Nov 14 '18 at 8:32
















    2














    Missing includes



    I think you need to include <stdio.h> and <stdlib.h> for successful compilation.



    Always check that allocations succeed



    Look at




    *buffer = malloc(16);
    (*buffer)[0] = 0;



    If malloc() returns a null pointer, then the assignment to its first element is undefined behaviour. Your program could crash, destroy your system, or (if you're unlucky) appear to work.



    Always check that input succeeds



    If getchar() returns EOF, we should stop reading. Note that by storing the result in a char, we lose the ability to distinguish EOF from valid input.



    Avoid output-only parameters



    Why do we return void, and instead write our result to a supplied pointer argument? I could understand accepting an argument if we were to re-use a buffer passed in, but we just discard it. I'd write this as



    /* caller must release allocated memory with free() */
    char *scan(void)


    Be careful of overflow



    If an input line reaches 255*16 = 4080 characters, size++ will overflow to zero. Then our realloc() acts as free(), and we find ourselves accessing memory out of bounds. I recommend using size_t for the length of allocated memory - allocation will fail before we reach the limits of size_t.



    Consider increasing the allocation increment



    This code reallocates every 16 chars. This makes for a lot of allocations for really long lines. One technique to avoid that, without hugely over-allocation for short lines, is to increase the increment as the buffer gets larger. So instead of always increasing by 16, we might double the buffer size instead, or perhaps double it and add 32. There are various strategies that can be used, with different performance implications (though the differences are likely small compared to the overhead of reading input at all).





    Improved version



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

    /* Read a line from standard input stream.

    Returns a buffer that must be released with free(),
    or a null pointer if none could be allocated.

    The result will end in a newline character if a
    full line was successfully read.
    */
    char *scan(void)
    {
    size_t capacity = 16;
    char *buffer = malloc(capacity);
    if (!buffer) {
    return NULL;
    }
    size_t i = 0;

    int c; /* current input character */
    while ((c = getchar()) != EOF) {
    if (i + 2 > capacity) {
    /* ensure space for c and terminating NUL */
    capacity *= 2;
    char *newbuf = realloc(buffer, capacity);
    if (!newbuf) {
    /* allocation failed - undo the read, terminate string, and return */
    ungetc(c, stdin);
    buffer[i] = '';
    return buffer;
    }

    buffer = newbuf;
    }

    /* We have enough space; now store it */
    buffer[i++] = (char)c;
    if (c == 'n') {
    break;
    }
    }

    if (i == 0) {
    /* we didn't read anything */
    free(buffer);
    return NULL;
    }

    buffer[i] = '';
    return buffer;
    }


    Demo



    #include <string.h>
    int main(void)
    {
    char *s;
    while ((s = scan())) {
    printf("%04zu %sn", strlen(s), s);
    free(s);
    }
    }





    share|improve this answer





















    • re: scan(void). Corner case: when a input error occurs, the code will, if some data was read prior, not return indication of a error. To cope, suggest before if (i == 0) { add if (c == EOF && !feof(stdin)) { i = 0; }.
      – chux
      Nov 13 '18 at 20:44










    • Like the ungetc(c, stdin); part on allocation failure - have to remember that good detail.
      – chux
      Nov 13 '18 at 20:45










    • When will getchar() return an EOF? I'm still new to C and I thought that it will simply wait for an input?
      – wispi
      Nov 13 '18 at 22:27










    • @chux, not sure I understand your first comment - if there's a failure after some input was read, we'll return what we can (which won't end in a newline, so distinguishable from 'good' input). A subsequent call will return NULL. Does the function comment need to be clearer, perhaps?
      – Toby Speight
      Nov 14 '18 at 8:27










    • @wispi - getchar() will return EOF at the end of the input stream, or when there's any failure when reading. The most likely causes of failures are OS-dependent, so you should consult the manual pages on your own system to increase your understanding.
      – Toby Speight
      Nov 14 '18 at 8:32














    2












    2








    2






    Missing includes



    I think you need to include <stdio.h> and <stdlib.h> for successful compilation.



    Always check that allocations succeed



    Look at




    *buffer = malloc(16);
    (*buffer)[0] = 0;



    If malloc() returns a null pointer, then the assignment to its first element is undefined behaviour. Your program could crash, destroy your system, or (if you're unlucky) appear to work.



    Always check that input succeeds



    If getchar() returns EOF, we should stop reading. Note that by storing the result in a char, we lose the ability to distinguish EOF from valid input.



    Avoid output-only parameters



    Why do we return void, and instead write our result to a supplied pointer argument? I could understand accepting an argument if we were to re-use a buffer passed in, but we just discard it. I'd write this as



    /* caller must release allocated memory with free() */
    char *scan(void)


    Be careful of overflow



    If an input line reaches 255*16 = 4080 characters, size++ will overflow to zero. Then our realloc() acts as free(), and we find ourselves accessing memory out of bounds. I recommend using size_t for the length of allocated memory - allocation will fail before we reach the limits of size_t.



    Consider increasing the allocation increment



    This code reallocates every 16 chars. This makes for a lot of allocations for really long lines. One technique to avoid that, without hugely over-allocation for short lines, is to increase the increment as the buffer gets larger. So instead of always increasing by 16, we might double the buffer size instead, or perhaps double it and add 32. There are various strategies that can be used, with different performance implications (though the differences are likely small compared to the overhead of reading input at all).





    Improved version



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

    /* Read a line from standard input stream.

    Returns a buffer that must be released with free(),
    or a null pointer if none could be allocated.

    The result will end in a newline character if a
    full line was successfully read.
    */
    char *scan(void)
    {
    size_t capacity = 16;
    char *buffer = malloc(capacity);
    if (!buffer) {
    return NULL;
    }
    size_t i = 0;

    int c; /* current input character */
    while ((c = getchar()) != EOF) {
    if (i + 2 > capacity) {
    /* ensure space for c and terminating NUL */
    capacity *= 2;
    char *newbuf = realloc(buffer, capacity);
    if (!newbuf) {
    /* allocation failed - undo the read, terminate string, and return */
    ungetc(c, stdin);
    buffer[i] = '';
    return buffer;
    }

    buffer = newbuf;
    }

    /* We have enough space; now store it */
    buffer[i++] = (char)c;
    if (c == 'n') {
    break;
    }
    }

    if (i == 0) {
    /* we didn't read anything */
    free(buffer);
    return NULL;
    }

    buffer[i] = '';
    return buffer;
    }


    Demo



    #include <string.h>
    int main(void)
    {
    char *s;
    while ((s = scan())) {
    printf("%04zu %sn", strlen(s), s);
    free(s);
    }
    }





    share|improve this answer












    Missing includes



    I think you need to include <stdio.h> and <stdlib.h> for successful compilation.



    Always check that allocations succeed



    Look at




    *buffer = malloc(16);
    (*buffer)[0] = 0;



    If malloc() returns a null pointer, then the assignment to its first element is undefined behaviour. Your program could crash, destroy your system, or (if you're unlucky) appear to work.



    Always check that input succeeds



    If getchar() returns EOF, we should stop reading. Note that by storing the result in a char, we lose the ability to distinguish EOF from valid input.



    Avoid output-only parameters



    Why do we return void, and instead write our result to a supplied pointer argument? I could understand accepting an argument if we were to re-use a buffer passed in, but we just discard it. I'd write this as



    /* caller must release allocated memory with free() */
    char *scan(void)


    Be careful of overflow



    If an input line reaches 255*16 = 4080 characters, size++ will overflow to zero. Then our realloc() acts as free(), and we find ourselves accessing memory out of bounds. I recommend using size_t for the length of allocated memory - allocation will fail before we reach the limits of size_t.



    Consider increasing the allocation increment



    This code reallocates every 16 chars. This makes for a lot of allocations for really long lines. One technique to avoid that, without hugely over-allocation for short lines, is to increase the increment as the buffer gets larger. So instead of always increasing by 16, we might double the buffer size instead, or perhaps double it and add 32. There are various strategies that can be used, with different performance implications (though the differences are likely small compared to the overhead of reading input at all).





    Improved version



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

    /* Read a line from standard input stream.

    Returns a buffer that must be released with free(),
    or a null pointer if none could be allocated.

    The result will end in a newline character if a
    full line was successfully read.
    */
    char *scan(void)
    {
    size_t capacity = 16;
    char *buffer = malloc(capacity);
    if (!buffer) {
    return NULL;
    }
    size_t i = 0;

    int c; /* current input character */
    while ((c = getchar()) != EOF) {
    if (i + 2 > capacity) {
    /* ensure space for c and terminating NUL */
    capacity *= 2;
    char *newbuf = realloc(buffer, capacity);
    if (!newbuf) {
    /* allocation failed - undo the read, terminate string, and return */
    ungetc(c, stdin);
    buffer[i] = '';
    return buffer;
    }

    buffer = newbuf;
    }

    /* We have enough space; now store it */
    buffer[i++] = (char)c;
    if (c == 'n') {
    break;
    }
    }

    if (i == 0) {
    /* we didn't read anything */
    free(buffer);
    return NULL;
    }

    buffer[i] = '';
    return buffer;
    }


    Demo



    #include <string.h>
    int main(void)
    {
    char *s;
    while ((s = scan())) {
    printf("%04zu %sn", strlen(s), s);
    free(s);
    }
    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 13 '18 at 9:18









    Toby Speight

    23.4k639111




    23.4k639111












    • re: scan(void). Corner case: when a input error occurs, the code will, if some data was read prior, not return indication of a error. To cope, suggest before if (i == 0) { add if (c == EOF && !feof(stdin)) { i = 0; }.
      – chux
      Nov 13 '18 at 20:44










    • Like the ungetc(c, stdin); part on allocation failure - have to remember that good detail.
      – chux
      Nov 13 '18 at 20:45










    • When will getchar() return an EOF? I'm still new to C and I thought that it will simply wait for an input?
      – wispi
      Nov 13 '18 at 22:27










    • @chux, not sure I understand your first comment - if there's a failure after some input was read, we'll return what we can (which won't end in a newline, so distinguishable from 'good' input). A subsequent call will return NULL. Does the function comment need to be clearer, perhaps?
      – Toby Speight
      Nov 14 '18 at 8:27










    • @wispi - getchar() will return EOF at the end of the input stream, or when there's any failure when reading. The most likely causes of failures are OS-dependent, so you should consult the manual pages on your own system to increase your understanding.
      – Toby Speight
      Nov 14 '18 at 8:32


















    • re: scan(void). Corner case: when a input error occurs, the code will, if some data was read prior, not return indication of a error. To cope, suggest before if (i == 0) { add if (c == EOF && !feof(stdin)) { i = 0; }.
      – chux
      Nov 13 '18 at 20:44










    • Like the ungetc(c, stdin); part on allocation failure - have to remember that good detail.
      – chux
      Nov 13 '18 at 20:45










    • When will getchar() return an EOF? I'm still new to C and I thought that it will simply wait for an input?
      – wispi
      Nov 13 '18 at 22:27










    • @chux, not sure I understand your first comment - if there's a failure after some input was read, we'll return what we can (which won't end in a newline, so distinguishable from 'good' input). A subsequent call will return NULL. Does the function comment need to be clearer, perhaps?
      – Toby Speight
      Nov 14 '18 at 8:27










    • @wispi - getchar() will return EOF at the end of the input stream, or when there's any failure when reading. The most likely causes of failures are OS-dependent, so you should consult the manual pages on your own system to increase your understanding.
      – Toby Speight
      Nov 14 '18 at 8:32
















    re: scan(void). Corner case: when a input error occurs, the code will, if some data was read prior, not return indication of a error. To cope, suggest before if (i == 0) { add if (c == EOF && !feof(stdin)) { i = 0; }.
    – chux
    Nov 13 '18 at 20:44




    re: scan(void). Corner case: when a input error occurs, the code will, if some data was read prior, not return indication of a error. To cope, suggest before if (i == 0) { add if (c == EOF && !feof(stdin)) { i = 0; }.
    – chux
    Nov 13 '18 at 20:44












    Like the ungetc(c, stdin); part on allocation failure - have to remember that good detail.
    – chux
    Nov 13 '18 at 20:45




    Like the ungetc(c, stdin); part on allocation failure - have to remember that good detail.
    – chux
    Nov 13 '18 at 20:45












    When will getchar() return an EOF? I'm still new to C and I thought that it will simply wait for an input?
    – wispi
    Nov 13 '18 at 22:27




    When will getchar() return an EOF? I'm still new to C and I thought that it will simply wait for an input?
    – wispi
    Nov 13 '18 at 22:27












    @chux, not sure I understand your first comment - if there's a failure after some input was read, we'll return what we can (which won't end in a newline, so distinguishable from 'good' input). A subsequent call will return NULL. Does the function comment need to be clearer, perhaps?
    – Toby Speight
    Nov 14 '18 at 8:27




    @chux, not sure I understand your first comment - if there's a failure after some input was read, we'll return what we can (which won't end in a newline, so distinguishable from 'good' input). A subsequent call will return NULL. Does the function comment need to be clearer, perhaps?
    – Toby Speight
    Nov 14 '18 at 8:27












    @wispi - getchar() will return EOF at the end of the input stream, or when there's any failure when reading. The most likely causes of failures are OS-dependent, so you should consult the manual pages on your own system to increase your understanding.
    – Toby Speight
    Nov 14 '18 at 8:32




    @wispi - getchar() will return EOF at the end of the input stream, or when there's any failure when reading. The most likely causes of failures are OS-dependent, so you should consult the manual pages on your own system to increase your understanding.
    – Toby Speight
    Nov 14 '18 at 8:32













    1
















    • realloc may fail. In that case, *buffer = newBuffer; without checking would result in a memory leak. Consider



          if (newBuffer) {
      *buffer = newBuffer;
      } else {
      handle_error_as_appropriate;
      }


    • Along the lines of the previous bullet, don't throw away valuable information you already obtained (in your case, the input length). Rather than being void, consider returning something useful. The standard Unix convention suggests returning a length of an input (or -1 on error).


    • The function presumes that the stream is infinite. It does not account for EOF of input errors.



    • I do not endorse meddling with input. You never know whether the newline character is significant or not. Refrain from



          if ((*buffer)[i] == 'n') {
      (*buffer)[i] = 0;


      Prefer



              (*buffer)[i + 1] = 0;


    • size *= 16 seems rather aggressive. Usual factor is 2.







    share|improve this answer




























      1
















      • realloc may fail. In that case, *buffer = newBuffer; without checking would result in a memory leak. Consider



            if (newBuffer) {
        *buffer = newBuffer;
        } else {
        handle_error_as_appropriate;
        }


      • Along the lines of the previous bullet, don't throw away valuable information you already obtained (in your case, the input length). Rather than being void, consider returning something useful. The standard Unix convention suggests returning a length of an input (or -1 on error).


      • The function presumes that the stream is infinite. It does not account for EOF of input errors.



      • I do not endorse meddling with input. You never know whether the newline character is significant or not. Refrain from



            if ((*buffer)[i] == 'n') {
        (*buffer)[i] = 0;


        Prefer



                (*buffer)[i + 1] = 0;


      • size *= 16 seems rather aggressive. Usual factor is 2.







      share|improve this answer


























        1












        1








        1








        • realloc may fail. In that case, *buffer = newBuffer; without checking would result in a memory leak. Consider



              if (newBuffer) {
          *buffer = newBuffer;
          } else {
          handle_error_as_appropriate;
          }


        • Along the lines of the previous bullet, don't throw away valuable information you already obtained (in your case, the input length). Rather than being void, consider returning something useful. The standard Unix convention suggests returning a length of an input (or -1 on error).


        • The function presumes that the stream is infinite. It does not account for EOF of input errors.



        • I do not endorse meddling with input. You never know whether the newline character is significant or not. Refrain from



              if ((*buffer)[i] == 'n') {
          (*buffer)[i] = 0;


          Prefer



                  (*buffer)[i + 1] = 0;


        • size *= 16 seems rather aggressive. Usual factor is 2.







        share|improve this answer
















        • realloc may fail. In that case, *buffer = newBuffer; without checking would result in a memory leak. Consider



              if (newBuffer) {
          *buffer = newBuffer;
          } else {
          handle_error_as_appropriate;
          }


        • Along the lines of the previous bullet, don't throw away valuable information you already obtained (in your case, the input length). Rather than being void, consider returning something useful. The standard Unix convention suggests returning a length of an input (or -1 on error).


        • The function presumes that the stream is infinite. It does not account for EOF of input errors.



        • I do not endorse meddling with input. You never know whether the newline character is significant or not. Refrain from



              if ((*buffer)[i] == 'n') {
          (*buffer)[i] = 0;


          Prefer



                  (*buffer)[i + 1] = 0;


        • size *= 16 seems rather aggressive. Usual factor is 2.








        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 12 '18 at 23:41

























        answered Nov 12 '18 at 23:19









        vnp

        38.6k13097




        38.6k13097






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207513%2fautomatically-scan-and-resize-buffer-in-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

            is 'sed' thread safe

            How to make a Squid Proxy server?