Automatically scan and resize buffer in C
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
add a comment |
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
It seems that (if yourUCHAR_MAX
is 255) this implementation will support reading of 4080 characters, not 256.
– Toby Speight
Nov 13 '18 at 8:32
add a comment |
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
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
beginner c
asked Nov 12 '18 at 22:20
wispi
404
404
It seems that (if yourUCHAR_MAX
is 255) this implementation will support reading of 4080 characters, not 256.
– Toby Speight
Nov 13 '18 at 8:32
add a comment |
It seems that (if yourUCHAR_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
add a comment |
2 Answers
2
active
oldest
votes
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);
}
}
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 beforeif (i == 0) {
addif (c == EOF && !feof(stdin)) { i = 0; }
.
– chux
Nov 13 '18 at 20:44
Like theungetc(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 returnEOF
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
|
show 2 more comments
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 is2
.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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);
}
}
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 beforeif (i == 0) {
addif (c == EOF && !feof(stdin)) { i = 0; }
.
– chux
Nov 13 '18 at 20:44
Like theungetc(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 returnEOF
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
|
show 2 more comments
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);
}
}
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 beforeif (i == 0) {
addif (c == EOF && !feof(stdin)) { i = 0; }
.
– chux
Nov 13 '18 at 20:44
Like theungetc(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 returnEOF
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
|
show 2 more comments
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);
}
}
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);
}
}
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 beforeif (i == 0) {
addif (c == EOF && !feof(stdin)) { i = 0; }
.
– chux
Nov 13 '18 at 20:44
Like theungetc(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 returnEOF
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
|
show 2 more comments
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 beforeif (i == 0) {
addif (c == EOF && !feof(stdin)) { i = 0; }
.
– chux
Nov 13 '18 at 20:44
Like theungetc(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 returnEOF
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
|
show 2 more comments
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 is2
.
add a comment |
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 is2
.
add a comment |
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 is2
.
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 is2
.
edited Nov 12 '18 at 23:41
answered Nov 12 '18 at 23:19
vnp
38.6k13097
38.6k13097
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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