I'm using this function to read, char by char, a text file or a stdin input
void readLine(FILE *stream, char **string) {
char c;
int counter = 0;
do {
c = fgetc(stream);
string[0] = (char *) realloc (string[0], (counter+1) * sizeof(char));
string[0][counter++] = c;
} while(c != ENTER && !feof(stream));
string[counter-1] = '\0';
}
But when I call it, my program crashed and I really don't know why, because I don't forget the 0-terminator and I'm convinced that I stored correctly the char sequence. I've verified the string length, but it appears alright.
This is an error:
do {
c = fgetc(stream);
// What happens here?!?
} while(c != ENTER && !feof(stream));
"What happens here" is that you add c to string before you've checked for EOF, whoops.
This is very ungood:
string[0] = (char *) realloc (string[0], (counter+1) * sizeof(char));
in a loop. realloc is a potentially expensive call and you do it for every byte of input! It is also a silly and confusing interface to ask for a pointer parameter that has (apparently) not been allocated anything -- passing in the pointer usually indicates that is already done. What if string were a static array? Instead, allocate in chunks and return a pointer:
char *readLine (FILE *stream) {
// A whole 4 kB!
int chunksz = 4096;
int counter = 0;
char *buffer = malloc(chunksz);
char *test;
int c;
if (!buffer) return NULL;
while (c = fgetc(stream) && c != ENTER && c != EOF) {
buffer[counter++] = (char)c;
if (counter == chunksz) {
chunksz *= 2;
test = realloc(buffer, chunksz);
// Abort on out-of-memory.
if (!test) {
free(buffer);
return NULL;
} else buffer = test;
}
}
// Now null terminate and resize.
buffer[counter] = '\0';
realloc(buffer, counter + 1);
return buffer;
}
That is a standard "power of 2" allocation scheme (it doubles). If you really want to submit a pointer, pre-allocate it and also submit a "max length" parameter:
void *readLine (FILE *stream, char *buffer, int max) {
int counter = 0;
int c;
while (
c = fgetc(stream)
&& c != ENTER
&& c != EOF
&& counter < max - 1
) buffer[counter++] = (char)c;
// Now null terminate.
buffer[counter] = '\0';
}
There are a few issues in this code:
fgetc() returns int.
Don't cast the return value of malloc() and friends, in C.
Avoid using sizeof (char), it's just a very clumsy way of writing 1, so multiplication by it is very redundant.
Normally, buffers are grown more than 1 char at a time, realloc() can be expensive.
string[0] would be more clearly written as *string, since it's not an array but just a pointer to a pointer.
Your logic around end of file means it will store the truncated version of EOF, not very nice.
Change this line
string[counter-1] = '\0';
to
string[0][counter-1] = '\0';
You want to terminate string stored at string[0].
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//the function
char* scan(char *string)
{
int c; //as getchar() returns `int`
string = malloc(sizeof(char)); //allocating memory
string[0]='\0';
for(int i=0; i<100 && (c=getchar())!='\n' && c != EOF ; i++)
{
string = realloc(string, (i+2)*sizeof(char)); //reallocating memory
string[i] = (char) c; //type casting `int` to `char`
string[i+1] = '\0'; //inserting null character at the end
}
return string;
}
char** bigScan(char **string)
{
int c;
string=malloc(sizeof(char *));
string[0]='\0';
for(int i=0;(c=getchar()!=EOF);i++)
{
*string = realloc(string, (i+2)*sizeof(char *)); //reallocating memory
string[i] = scan(string[i]); //type casting `int` to `char`
string[i+1] = '\0'; //inserting null character at the end
}
return string;
}
int main(void)
{
char **buf; //pointer to hold base address of string
buf=bigScan(buf);
printf("%s\n",buf[0] );
}
So basically the scan function reads each line until either EOF or new line.The job of bigScan is to read multiple lines (pointer to strings) by invoking the scan function until we hit EOF. So essentially the big scan returns pointer to pointers and we can read the entire text using this.
What am I doing wrong in my approach ?
Basically invoking the scan function in my bigScan until I Hit EOF.
Ideal Input:
"Hi guys and girls
This is a message in multiple lines."
Ideal Output:
"Hi guys and girls
This is a message in multiple lines."
The (c=getchar()!=EOF) inside bigScan is invalid. It assigns the value of 1 or 0 to c, as the bool value is the result of != comparison.
The getchar() inside bigScan will make you loose one character per line, as that character is nowhere saved.
The allocation in bigScan is invalid. You shouldn't allocate the memory for string *string = realloc(string, but you should allocate the memory for pointers themselves, ie. string = realloc(string, ... sizeof(char*)).
NULL is the terminating value used for pointers. Don't use '\0' for pointers.
Use size_t to store sizes.
There is little point in passing parameters value if you are overwriting them. In this function the variable a is unused void f(int a) { a = 1; } as the variable string in your both functions are assigned immediately after entering the function.
The function scan has a hard limit of i<100 characters.
Below is somewhat fixed version of your functions. With also renamed variables. And removed parameters. And different indentation. And with assertions from the standard #include <assert.h> to use as a primitive error checking. And with ungetc so the character read in bigScan doesn't disappear. And I haven't run this code, so it has ton of errors.
char* scan(void)
{
char *string = malloc(sizeof(*string));
assert(string != NULL);
string[0] = '\0';
size_t stringlen = 1;
for(int c; (c=getchar()) != '\n' && c != EOF;) {
void * const ptr = realloc(string, (stringlen + 1) * sizeof(*string));
assert(ptr != NULL);
stringlen++;
string[stringlen - 2] = c;
string[stringlen - 1] = '\0'; //inserting null character at the end
}
return string;
}
char** bigScan(void)
{
char **strings = malloc(sizeof(*strings));
assert(strings != NULL);
strings[0] = NULL;
size_t stringslen = 1;
for(int c; (c = getchar()) != EOF;) {
ungetc(c);
void * const ptr = realloc(strings, (stringslen + 1) * sizeof(*strings));
assert(ptr != NULL);
strings = ptr;
stringslen++;
strings[stringslen - 2] = scan();
strings[stringslen - 1] = NULL;
}
return strings;
}
I am given an assignment to take in and store a string using a function, however, I am given some restrictions.
Only able to use getchar() to take in user input character by character
No assumption of length of the input (Not allowed to create a array of size 100 for example)
Not allowed to read the input twice, for example, using the first round of input to count string size and then ask the user to input again after creating an array of the string's size that was counted on the first round.
Not allowed to create a large buffer so a constant size buffer means memory will be wasted if the input is 1 character for example
int read_string()
{
char* input;
int counter = 0;
while (( input = getchar()) != '\n') //read until detect '\n'
{
printf("%c\n",input);
counter = counter + 1;
}
printf("Length of string: %d\n", counter);
}
I currently have no idea how to store character by character and dynamically resize an "array" like vectors equivalent in C++. C does not have vectors based on my research.
Based on my code now, when i type in "Hello",
the output will be
h
e
l
l
o
but I do not know how to store each character in a dynamic array
You'd have to use the realloc function, if you want to dynamically increase the size with every new character that you read.
When you use realloc, the content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location. If the function fails to allocate the requested block of memory, a null pointer is returned.
For every character that I read, I increment buffsize, but I do allocate buffsize + 1. Why? Because I need one extra position for the NULL terminator.
The last free position for a letter would be buffsize - 1 in this case and the last one will be assigned at the end of the while loop.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t buffsize = 0;
char *buffer = NULL;
char *temp;
char input;
while ((input = getchar()) != '\n') {
printf("%c\n", input);
/* Incraese the size & realloc */
++buffsize;
temp = realloc(buffer, (buffsize + 1) * sizeof(char));
if (!temp) {
printf("Error reallocating buffer!\n");
exit(1);
}
/* Setting the new read char */
buffer = temp;
buffer[buffsize - 1] = input;
}
if (buffsize) {
buffer[buffsize] = '\0';
printf("Result = [%s]\n", buffer);
} else {
printf("Empty input!\n");
}
printf("String size=%lu\n", buffsize);
/* Clean */
free(buffer);
return 0;
}
A bit more generic - function which adds a char to the string. Initially pointer should be NULL and it will take it into account automatically
char *addchar(char **str, int c)
{
size_t len= 0;
char *tmp;
if(*str)
{
len = strlen(*str);
}
tmp = realloc(*str, len + 2);
if(tmp)
{
*str = tmp;
tmp[len] = c;
tmp[len + 1] = 0;
}
return tmp;
}
and usage - a bit different than yours
int main()
{
char *mystring = NULL;
int input;
while (( input = getchar()) != EOF)
{
if(input == '\n' || input == '\r') continue;
if(!addchar(&mystring, input))
{
printf("\nMemory allocation error\n");
}
else
{
printf("String length %zu\n", strlen(mystring));
}
}
}
First off, the function getchar() returns and int not char * so you should not assign its return value to the pointer input declared in your code as char* input;
You should start by declaring an int variable; could be called len ; and initialize it with the value of 0. Next you should call the function malloc() and feed it 1 to allocate 1 byte of memory to hold a single character, and assign its return value to the pointer input, like the following:
int len = 0;
input = malloc(1);
Then you should store the NUL-terminating character '\0' in the allocated memory:
input[0] = '\0';
Then you create an int variable since the return value of getchar() is int. This variable which could be called ch shall store the user input.
Then you increase the size of your allocated storage to accommodate the new character:
input = realloc(input, len + 1);
input[len] = ch;
len++;
The entire code should look like the following:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int len = 0;
char *input = malloc(1);
input[0] = '\0';
int ch;
while ((ch = getchar()) != '\n')
{
input = realloc(input, len + 1);
input[len] = ch;
len++;
}
input[len] = '\0';
printf("You entered: %s\n", input);
printf("Length of str: %d\n", len);
free(input);
return 0;
}
I wrote this simple readline function, it can return each line length but it doesn't return a pointer to the allocated buffer. Another issue is the last line ignored(it doesn't return it):
FILE *passFile = NULL;
char *current = NULL;
size_t len = 0;
passFile = fopen("pass.txt", "r");
while(readline(passFile, ¤t, &len) != -1) {
printf("%s\n", current); // SEGMENTAION FAULT
printf("%d\n", len);
free(current);
current = NULL;
}
ssize_t
readline(FILE *file, char **bufPtr, size_t *len)
{
char c, *buf = NULL;
size_t n = 0;
buf = (char*)malloc(sizeof(char));
while((c = fgetc(file)) != '\n' && (c != EOF)) {
buf[n] = c;
++n;
buf = realloc(buf, n + 1);
}
buf[n] = '\0';
*bufPtr = buf;
*len = n;
if(c == EOF) // reach end of file
return -1;
return 0;
}
Your readline() function is not returning a pointer to allocated memory. In your call, current is never set, so the pointer is invalid and you get the error.
In C, functions are "call by value". Inside readline(), bufPtr is a copy of whatever was passed to readline(). Assigning to bufPtr merely overwrites the local copy and does not return a value that the calling code can see.
In pseudocode:
TYPE a;
define function foo(TYPE x)
{
x = new_value;
}
foo(a); // does not change a
This only changes the local copy of x and does not return a value. You change it to use a pointer... the function still gets a copy, but now it's a copy of a pointer, and it can use that pointer value to find the original variable. In pseudocode:
TYPE a;
define function foo(TYPE *px)
{
*px = new_value;
}
foo(&a); // does change a
Now, to change your function:
ssize_t
readline(FILE *file, char **pbufPtr, size_t *len)
{
// ...deleted...
buf[n] = '\0';
*pbufPtr = buf;
// ...deleted...
}
And you call it like so:
while(readline(passFile, ¤t, &len) != -1)
P.S. It is not a good idea to call realloc() the way you do here. It's potentially a very slow function, and for an input string of 65 characters you will call it 65 times. It would be better to use an internal buffer for the initial file input, then use malloc() to allocate a string that is just the right size and copy the string into the buffer. If the string is too long to fit in the internal buffer at once, use malloc() to get a big-enough place to copy out the part of the string you have in the internal buffer, then continue using the internal buffer to copy more of the string, and then call realloc() as needed. Basically I'm suggesting you have an internal buffer of size N, and copy the string in chunks of N characters at a time, thus minimizing the number of calls to realloc() while still allowing arbitrary-length input strings.
EDIT: Your last-line problem is that you return -1 when you hit end of file, even though there is a line to return.
Change your code so that you return -1 only if c == EOF and n == 0, so a final line that ends with EOF will be correctly returned.
You should also make readline() use the feof() function to check if file is at end-of-file, and if so, return -1 without calling malloc().
Basically, when you return -1, you don't want to call malloc(), and when you did call malloc() and copy data into it, you don't want to return -1! -1 should mean "you got nothing because we hit end of file". If you got something before we hit end of file, that's not -1, that is 0. Then the next call to readline() after that will return -1.
In your readline function you pass current by value. So if you change bufPtr inside your function, it doesn't change value of current outside. If you want to change value of current pass it by reference: ¤t and change readline() parameter to char **bufPTR.
You could pass current the way you did if you wanted to change something it points to, but you want to change where it points in first place.
replace your readlinefunction with this
char* readline(FILE *file, size_t *len)
{
char c, *buf = NULL;
size_t n = 0;
buf = (char*)malloc(sizeof(char));
while((c = fgetc(file)) != '\n' && (c != EOF)) {
buf[n] = c;
++n;
buf = realloc(buf, n + 1);
}
buf[n] = '\0';
bufPtr = buf;
*len = n;
if(c == EOF) // reach end of file
return NULL;
return buf;
}
and then in main replace this line while(readline(passFile, current, &len) != -1) with this while((current = readline(passFile, &len) != NULL)
Now it works:
ssize_t
readline(FILE *file, char **bufPtr, size_t *len)
{
if(feof(file)) // reach end of file
return -1;
char c, *buf = NULL;
size_t n = 0, portion = CHUNK;
buf = (char*)malloc(sizeof(char) * CHUNK);
while((c = fgetc(file)) != '\n' && (c != EOF)) {
buf[n] = c;
++n;
if(n == portion) {
buf = realloc(buf, CHUNK + n);
portion += n;
}
}
buf[n] = '\0';
*bufPtr = buf;
*len = n;
return 0;
}
I am trying to use a function that returns char * buffer to trap random user input from standard input and return a char* (that is, a string) with the input until '\n' or '\0' is detected as input.
However, the function user_input() crashed at the second occurence of c = getchar(); near the end of the function (at the //Error Here comment).
What am I doing wrong?
char* user_input(){
char *buffer=NULL;
size_t num_read = 0;
size_t buffer_size = 100;
char c = '\0';
char *new_buffer=NULL;
buffer = malloc(buffer_size);
fflush(stdin);
c = getchar();
while ( c != '\n' || c !='\0' ) {
if (num_read >= buffer_size) {
new_buffer=NULL;
buffer_size *= 2; // try a buffer that's twice as big as before
new_buffer = realloc(buffer, buffer_size);
if (new_buffer == NULL) {
free(buffer);
return NULL;
/* Abort - out of memory */
}
buffer = new_buffer;
}
buffer[num_read] = c;
num_read++;
c = getchar(); //Error Here
}//while
buffer[num_read] = '\0';
return buffer;
}
while ( c != '\n' || c !='\0' ) {
should use && instead of || or the loop will never exit
while ( c != '\n' && c !='\0' ) {
I built it and it worked although there are other bugs in the code such as the "buffer[num_read] = '\0';" at the end could overflow the buffer if there are exactly buffer_size items in the array.
Here are the issues that I found:
You cannot call fflush() on stdin. It leads to undefined behavior. fflush() is only for output streams.
The type for c should be an int. The getchar() will return EOF when there is no more input, and EOF is a value not equal to any valid value for unsigned char. That is why getchar() returns an int, so your variable receiving the return value of getchar() should match that type.
The sense of the while check is incorrect. You will only leave the loop if c equals both \n and \0 at the same time, which is not possible. Thus the loop will never exit. If you actually ended the input given to your program, you probably entered an infinite loop, continually allocating until your system ran out of memory. So, you want to leave the loop if c equals \n or \0.
You should add a check to leave the loop if c is EOF.
You should make sure num_read is less than buffer_size before you assign the \0 character. This can be done by moving your realloc() code to be at the bottom of the while loop instead of at the top.
With these changes, the code looks like:
char *user_input() {
char *buffer = NULL;
size_t num_read = 0;
size_t buffer_size = 100;
int c = '\0';
char *new_buffer = NULL;
buffer = malloc(buffer_size);
c = getchar();
while (!(c == EOF || c == '\n' || c == '\0')) {
assert(num_read < buffer_size);
buffer[num_read++] = c;
if (num_read >= buffer_size) {
buffer_size *= 2; // try a buffer that's twice as big as before
new_buffer = realloc(buffer, buffer_size);
if (new_buffer == NULL) {
free(buffer);
return NULL;
}
buffer = new_buffer;
}
c = getchar();
} //while
assert(num_read < buffer_size);
buffer[num_read] = '\0';
return buffer;
}
I have modified your code below. Try to run it as is, using the 'q' character at first, then you can experiment with other exit criteria later. By the way, your code worked without modification and did not crash for me (unless buffer overrun occured, but it would never leave the while loop otherwise (as Brian Walker pointed out). In any case, Try this in any ANSI C compiler: (just don't enter more than 1000 entries :)
#include <ansi_c.h>
char* user_input(void);
int main(void)
{
char *buf;
buf = malloc(1000);
//SearchDirectory("C:\\dev");
sprintf(buf, "%s", user_input());
printf("%s", buf);
free(buf);
return 0;
}
char* user_input(void){
char *buffer=NULL;
size_t num_read = 0;
size_t buffer_size = 100;
char c = '\0';
char *new_buffer=NULL;
buffer = malloc(buffer_size);
fflush(stdin);
c = getchar();
while ( c != 'q' ) {
if (num_read >= buffer_size) {
new_buffer=NULL;
buffer_size *= 2; // try a buffer that's twice as big as before
new_buffer = realloc(buffer, buffer_size);
if (new_buffer == NULL) {
free(buffer);
return NULL;
/* Abort - out of memory */
}
buffer = new_buffer;
}
buffer[num_read] = c;
num_read++;
c = getchar();
}//while
buffer[num_read] = '\0';
return buffer;
}
I want to read input from user using C program. I don't want to use array like,
char names[50];
because if the user gives string of length 10, then the remaining spaces are wasted.
If I use character pointer like,
char *names;
then I need to allocate memory for that in such a way of,
names = (char *)malloc(20 * sizeof(char));
In this case also, there is a possibility of memory wastage.
So, what I need is to dynamically allocate memory for a string which is of exactly same as the length of the string.
Lets assume,
If the user input is "stackoverflow", then the memory allocated should be of 14 (i.e. Length of the string = 13 and 1 additional space for '\0').
How could I achieve this?
Read one character at a time (using getc(stdin)) and grow the string (realloc) as you go.
Here's a function I wrote some time ago. Note it's intended only for text input.
char *getln()
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch) {
ch = getc(stdin);
/* Check if we need to stop. */
if (ch == EOF || ch == '\n')
ch = 0;
/* Check if we need to expand. */
if (size <= index) {
size += CHUNK;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
/* Actually store the thing. */
line[index++] = ch;
}
return line;
}
You could have an array that starts out with 10 elements. Read input character by character. If it goes over, realloc another 5 more. Not the best, but then you can free the other space later.
You can also use a regular expression, for instance the following piece of code:
char *names
scanf("%m[^\n]", &names)
will get the whole line from stdin, allocating dynamically the amount of space that it takes. After that, of course, you have to free names.
If you ought to spare memory, read char by char and realloc each time. Performance will die, but you'll spare this 10 bytes.
Another good tradeoff is to read in a function (using a local variable) then copying. So the big buffer will be function scoped.
Below is the code for creating dynamic string :
void main()
{
char *str, c;
int i = 0, j = 1;
str = (char*)malloc(sizeof(char));
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
str = (char*)realloc(str, j * sizeof(char));
// store read character by making pointer point to c
str[i] = c;
i++;
j++;
}
str[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", str);
free(str); // important step the pointer declared must be made free
}
First, define a new function to read the input (according to the structure of your input) and store the string, which means the memory in stack used. Set the length of string to be enough for your input.
Second, use strlen to measure the exact used length of string stored before, and malloc to allocate memory in heap, whose length is defined by strlen. The code is shown below.
int strLength = strlen(strInStack);
if (strLength == 0) {
printf("\"strInStack\" is empty.\n");
}
else {
char *strInHeap = (char *)malloc((strLength+1) * sizeof(char));
strcpy(strInHeap, strInStack);
}
return strInHeap;
Finally, copy the value of strInStack to strInHeap using strcpy, and return the pointer to strInHeap. The strInStack will be freed automatically because it only exits in this sub-function.
This is a function snippet I wrote to scan the user input for a string and then store that string on an array of the same size as the user input. Note that I initialize j to the value of 2 to be able to store the '\0' character.
char* dynamicstring() {
char *str = NULL;
int i = 0, j = 2, c;
str = (char*)malloc(sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
exit(EXIT_FAILURE);
}
while((c = getc(stdin)) && c != '\n')
{
str[i] = c;
str = realloc(str,j*sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
free(str);
exit(EXIT_FAILURE);
}
i++;
j++;
}
str[i] = '\0';
return str;
}
In main(), you can declare another char* variable to store the return value of dynamicstring() and then free that char* variable when you're done using it.
Here's a snippet which I wrote which performs the same functionality.
This code is similar to the one written by Kunal Wadhwa.
char *dynamicCharString()
{
char *str, c;
int i = 0;
str = (char*)malloc(1*sizeof(char));
while(c = getc(stdin),c!='\n')
{
str[i] = c;
i++;
realloc(str,i*sizeof(char));
}
str[i] = '\0';
return str;
}
char* load_string()
{
char* string = (char*) malloc(sizeof(char));
*string = '\0';
int key;
int sizer = 2;
char sup[2] = {'\0'};
while( (key = getc(stdin)) != '\n')
{
string = realloc(string,sizer * sizeof(char));
sup[0] = (char) key;
strcat(string,sup);
sizer++
}
return string;
}
int main()
{
char* str;
str = load_string();
return 0;
}
realloc is a pretty expensive action...
here's my way of receiving a string, the realloc ratio is not 1:1 :
char* getAString()
{
//define two indexes, one for logical size, other for physical
int logSize = 0, phySize = 1;
char *res, c;
res = (char *)malloc(sizeof(char));
//get a char from user, first time outside the loop
c = getchar();
//define the condition to stop receiving data
while(c != '\n')
{
if(logSize == phySize)
{
phySize *= 2;
res = (char *)realloc(res, sizeof(char) * phySize);
}
res[logSize++] = c;
c = getchar();
}
//here we diminish string to actual logical size, plus one for \0
res = (char *)realloc(res, sizeof(char *) * (logSize + 1));
res[logSize] = '\0';
return res;
}