Confusion on Malloc behavior, why it last input is not taken? - c

This is a snippet of a program I am working on. I wanted to get information from the user, where the target variable cannot have predefined memory. For some reason my function does not work for the last section of the code. Any help will be appreciated.
Current Output:
Enter your name: Daniel
Hi Danie (expected as I put the limit to 5 characters)
Enter your phone number: 123456789
123456789
Enter your Note: (Here it breaks and does not print the contactNote variable.)
Here is the code:
char *getwords(int numberoftimes) {
char *words = malloc(sizeof(char));
int index = 0;
int character = EOF;
int size = 0;
int increase = 1;
int counter = 0;
char *temp;
while (character) {
character = getc(stdin);
if (numberoftimes == 0) {
if (character == '\n') {
character = 0;
}
} else if (counter == numberoftimes || character == '\n') {
character = 0;
}
if (size <= index) {
size += increase;
temp = realloc(words, size);
if (!temp) {
free(words);
words = NULL;
break;
}
words = temp;
}
words[index++] = character;
counter++;
}
return words;
}
int main() {
char *contactName, *contactNote;
long contactNumber;
printf("\nEnter your name: ");
char *getwords();
char *Name = getwords(5);
printf("\nHi %s\n", Name);
printf("\nEnter your phone number: ");
scanf("%lu", &contactNumber);
printf("\n%lu\n", contactNumber);
printf("\nEnter your Note: ");
char *getwords();
char *Note = getwords(0);
printf("\n%s\n", Note);
}

scanf() for the contact number leaves the ENTER sitting in the [keyboard] input buffer.
int main() {
char *contactName, *contactNote; // unused variables
long contactNumber;
printf("\nEnter your name: ");
char* getwords(); // unnecessary function declaration
char *Name = getwords(5);
printf("\nHi %s\n", Name);
printf("\nEnter your phone number: ");
scanf("%lu", &contactNumber); // leaves <ENTER> in buffer
printf("\n%lu\n", contactNumber);
printf("\nEnter your Note: ");
char* getwords(); // unnecessary function declaration
char *Note = getwords(0); // empty line because of previous <ENTER>
printf("\n%s\n", Note);
}
I suggest you also use getwords() for the number, then convert to long with strtol().

There are multiple problems in your code:
mixing getc() and scanf() is tricky as scanf() leaves the trailing newline pending in stdin so getc() reads this newline immediately. You should read all of your inputs with getwords().
the extra char *getwords(); declarations inside the body of main() are redundant and confusing.
getwords() is too complicated, especially for exiting the loop.
you do not always check for memory allocation error.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
char *getwords(const char *prompt, int maxlen) {
char *words = malloc(sizeof(char));
int index = 0;
int size = 0;
char *temp;
if (words == NULL)
return NULL;
printf("%s", prompt);
for (;;) {
int character = getc(stdin);
if (character == EOF || character == '\n')
break;
if (index < maxlen) {
if (index >= size) {
size += 1;
temp = realloc(words, size + 1);
if (!temp) {
free(words);
return NULL;
}
words = temp;
}
words[index++] = character;
}
}
words[index] = '\0';
return words;
}
int main() {
char *Name = getwords("\nEnter your name: ", 5);
if (!Name)
return 1;
printf("\nHi %s\n", Name);
char *contact = getwords("\nEnter your phone number: ", 20);
if (!contact)
return 1;
long contactNumber = 0;
sscanf(contact, "%lu", &contactNumber);
printf("\n%lu\n", contactNumber);
char *Note = getwords("\nEnter your Note: ", 10);
if (!Note)
return 1;
printf("\n%s\n", Note);
return 0;
}

Related

Why is my function to reverse string in c not working?

I am writing some C Code where the user enters the desired string size and then a string which will be reversed then printed (as opposed to being printed in reverse.) I also would like to mention that I don't want to use external libraries, the whole point of this is to be able to do it manually. I used dynamic memory allocation to create a string of a size inputted by the user and called a "Reverse Array" function. Everything works fine until the function is called. My method for reversing the string followed the same principle as reversing a normal array but instead of moving integers around I moved characters around. Can you explain to me what I have done wrong?
My Code:
#include <stdio.h>
#include <stdlib.h>
int RvsArr(char *Str, int end)
{
int start = 0;
char tmp;
while (start < end)
{
tmp = Str[start];
Str[start] = Str[end];
Str[end] = tmp;
start++;
end--;
}
printf("%s", Str);
return 0;
}
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf("%i", &ArrSz);
char *Str;
Str = (char *)malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf("%s", Str);
RvsArr(Str, ArrSz);
free(Str);
return 0;
}
You need to reverse the actual string, not the full buffer.
char *RvsArr(char* Str)
{
char *end, *wrk = Str;
char tmp;
if(wrk && *wrk)
{
end = Str + strlen(wrk) - 1;
while(wrk < end)
{
tmp = *wrk;
*wrk++ = *end;
*end-- = tmp;
}
}
return Str;
}
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf(" %i", &ArrSz);
char* Str;
Str = malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf(" %s", Str);
printf("\n`%s`\n", RvsArr(Str));
free(Str);
return 0;
}
https://godbolt.org/z/azob5s
For starters the user can enter a string the size of which can be less than the size of the dynamically allocated character array that stores the string.
So passing the size of the array does not make a sense. The size of the array is not the same as the size of the entered string.
Also this expression Str[end] access memory beyond the allocated array in the first iteration of the while loop.
And the return type int also does not make a sense.
Apart from this the function should not output anything. It is the caller of the function that will decide to output the result string or not.
Pay attention to that this call
scanf("%s", Str);
is unsafe. It would be better to use the function fgets. For example
fgets( Str, ArrSz, stdin );
In this case you will need to remove the new line character '\n' that the function can append to the entered string.
Without using standard string functions the function can be defined the following way as it is shown in the demonstrative program below.
Instead of the senseless return type int the function returns a pointer to the first character of the reversed string.
#include <stdio.h>
char * RvsArr( char *s )
{
char *last = s;
while ( *last ) ++last;
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char s[] = "Hello World!";
puts( s );
puts( RvsArr( s ) );
return 0;
}
The program output is
Hello World!
!dlroW olleH
If you are allowed to use standard string functions then the function RvsArr can look the following way (provided that the header <string.h> is included)
char * RvsArr( char *s )
{
char *last = s + strlen( s );
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
Character arrays or string in c(as it is generally referred to) requires one extra byte which store null character ('\o' or 0) to indicate the end of string. You can store ArrSz - 1 character in your array and ArrSz byte stores the termination character('\o' or 0).
int RvsArr(char* Str, int end)
{
if (Str == 0 || end <= 1)
return 0;
int start = 0;
char tmp;
while(start < end)
{
tmp = Str[start];
Str[start] = Str[--end]; // pre decrement the counter to last char
Str[end] = tmp;
start++;
}
printf("%s", Str);
return 0;
}
or in other version
int RvsArr(char* Str, int end)
{
if (Str == 0 || end <= 1)
return 0;
int start = 0;
int last = end - 1;
char tmp;
while(start < last)
{
tmp = Str[start];
Str[start] = Str[last];
Str[last] = tmp;
start++;
last--;
}
printf("%s", Str);
return 0;
}
And some changes in main function are
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf("%i", &ArrSz);
char *Str;
Str = (char *)malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf("%s", Str);
Str[ArrSz] = '\0'; // Here we have no control on how many characters are read, scan is a security vulnerability becuse of this
printf("Input=%s, len=%d\n", Str, strlen(Str));
RvsArr(Str, strlen(Str));
free(Str);
return 0;
}

How do I dynamically allocate memory in C

I'm trying to make a word counter program and want to dynamically allocate memory for the string without extra space. Here's my code so far:
#include <stdio.h>
#include <stdlib.h>
char *strmalloc(char *string);
char *user_input = NULL;
int main(void) {
printf("Enter a sentence to find out the number of words: ");
strmalloc(user_input);
printf("You entered %s", user_input);
return 0;
}
char *strmalloc(char *string) {
char *tmp = NULL;
size_t size = 0, index = 0;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
if (size <= index) {
size += 1;
tmp = realloc(string, size);
if (!tmp) {
free(string);
string = NULL;
break;
}
string = tmp;
}
string[index++] = ch;
}
return string;
}
Here's the output:
Enter a sentence to find out the number of words: Testing program
You entered (null)
Process finished with exit code 0
I thought that in the while loop, I reallocate 1 byte of memory until the string fits just right? What am I doing wrong?
In your functiuon:
char *strmalloc(char *string) { ===> char *strmalloc(char **string) {
tmp = realloc(string, size); ===> tmp = realloc(*string, size);
string = NULL; ===> *string = NULL;
string = tmp; ===> *string = tmp;
string[index++] = ch; ===> (*string)[index++] = ch;
return string; ===> return *string;
In the calling function:
strmalloc(user_input); ===> strmalloc(&user_input);

How to clear buffer after reading an input in c?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void generarDimension(int, void **, int);
void reallocarDimensiones(int, void **, int);
void preguntarValor(int *);
char *generarCadena(char *);
typedef struct listaAlu{//this is a list of students
char cedula[7];//this means id
char *nombreApellido;//this means name and lastname
short curso;//this means the year of the student in college/school
unsigned short anho;//and this means year-E.g: 2017
};
int main(void){
struct listaAlu *alu = NULL;
int salir=1;
char c;
unsigned int cont = 0;
unsigned int i;
size_t size = 0;
struct listaAlu *temp = NULL;
while(salir!=0){//Condition until user press exit option
printf("Agregar Alumno?Ingrese 1 para Agregar, y 0 para salir\n");//This means "Add student?Press 1 to add, and 0 to exit
preguntarValor(&salir);//this verifies user input
if(salir==1){//if user adds then it asks info of the student
cont++;
if ( NULL == ( temp = realloc ( alu, size + 2))) {//realloc for each character input and '\0'
fprintf ( stderr, "realloc problem\n");
}//this is for increasing the number of students
alu = temp;
printf("Ingrese Cedula:\n");//This means "Enter id"
scanf("%s", &(alu+(size))->cedula);
printf("Ingrese Nombre y Apellido:\n");//This means "Enter name and lastname"
(alu+(size))->nombreApellido = generarCadena((alu+(size))->nombreApellido);
printf("Ingrese Curso:\n");//This means enter college/school year
scanf("%hd", &(alu+(size))->curso);
printf("Ingrese Anho:\n");//and this means "Enter year"
scanf("%hd", &(alu+(size))->anho);
size++;
}
}
for(i=0;i<cont;i++){
printf("\tAlumno %d\n", i+1);
printf("Nombre:\t%s\n", (alu+i)->nombreApellido);
printf("Cedula:\t%s\n", (alu+i)->cedula);
printf("Curso:\t%d\n", (alu+i)->curso);
printf("Anho:\t%d\n", (alu+i)->anho);
}//This prints Everything the user entered
free(alu);
return 0;
}//Sorry for writing my program entirely on the main >.<
void generarDimension(int bloques, void **ptr, int tamanho){
void **ptrAux;
*ptrAux = malloc(bloques * tamanho);
if(*ptrAux==NULL){
printf("No se pudo almacenar memoria\n");
}else{
*ptr = *ptrAux;
free(ptrAux);
}
}//this I didn't use, but it is for generating an array through a pointer
void reallocarDimensiones(int bloques, void **ptr, int tamanho){
void **ptrAux;
*ptrAux = realloc(*ptr,bloques * tamanho);
if(*ptrAux==NULL){
printf("No se pudo almacenar memoria\n");
}else{
*ptr = *ptrAux;
free(ptrAux);
}
}//This I didn't either, but it is for reallocating any given pointer
void preguntarValor(int *n){
long entero, lector;
*n=-2;
do{
printf("\nSi ingresa otro numero o caracter, vuelva a ingresar opcion\n");
while(!scanf("%d", &entero)){
while((lector=getchar()) !='\n' && lector !=EOF );
}
*n=entero;
}while(*n>1 || *n<0);//You can change this parameters according to the numbers you want
}//This subrutine scans only integers between 1 and 0
char *generarCadena(char *scaneado){
char *temp = NULL;
int in = 0;
size_t size = 0;
while ( '\n' != ( in = getchar ( ))) {//loop until newline
if ( NULL == ( temp = realloc ( scaneado, size + 2))) {//realloc for each character input and '\0'
fprintf ( stderr, "realloc problem\n");
return scaneado;
}
scaneado = temp;
scaneado[size] = in;//set input
scaneado[size + 1] = '\0';//terminate
size++;
}
return scaneado;
}//This subrutine is for geting an input of chars of any given length
This is a program to store a college/school student list, I want to know how to improve this code, however in the part where I ask the user to enter strings, on the second one I can't enter anything. And if I try to enter more than 2 students, my code doesn't print all the info of the students I entered
struct listaAlu *temp = NULL;
temp = realloc ( alu, size + 2);//<- wrong size
realloc(alu, size + 2) will allocate only 2 bytes in the first run. But you need much more than that. The total size needed is number of elements in the array multiply by the size of the structure. That is sizeof(struct listaAlu) which is about 15 bytes.
realloc( alu, sizeof(struct listaAlu) * (size + 1) );
You don't need to increment the size by 2.
Make sure to check the input at the right places. Clear the input when scanf fails.
To get first name and last name, you can use fgets and strdup
There are major problems with generarDimension and reallocarDimensiones. You may want to leave those out.
struct listaAlu{
char cedula[7];//this means id
char *nombreApellido;//this means name and lastname
short curso;//this means the year of the student in college/school
unsigned short anho;//and this means year-E.g: 2017
};
void clear()
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
int main(void)
{
struct listaAlu *alu = NULL;
size_t size = 0;
while(1)
{
alu = realloc( alu, sizeof(struct listaAlu) * (size + 1) );
if (!alu)
{
fprintf(stderr, "realloc problem\n");
break;
}
char buf[256] = { 0 };
printf("Enter id:\n");
fgets(buf, sizeof(buf), stdin);
buf[strcspn(buf, "\r\n")] = 0;
buf[sizeof(alu[size].cedula) - 1] = 0;
strcpy(alu[size].cedula, buf);
printf("Enter name and lastname:\n");
fgets(buf, sizeof(buf), stdin);
buf[strcspn(buf, "\r\n")] = 0;
alu[size].nombreApellido = _strdup(buf);
for(;;)
{
printf("Enter college/school year:\n");
if (scanf("%hd", &alu[size].curso) == 1)
break;
printf("input error\n");
clear();
}
for(;;)
{
printf("Enter year:\n");
if (scanf("%hd", &alu[size].anho) == 1)
break;
printf("input error\n");
clear();
}
size++;
printf("Press 1 to continue\n");
char input;
scanf(" %c", &input);
if(input != '1')
break;
clear();
}
for(size_t i = 0; i < size; i++)
{
printf("Alumno %d\n", i);
printf("Nombre:\t%s\n", alu[i].nombreApellido);
printf("Cedula:\t%s\n", alu[i].cedula);
printf("Curso:\t%hd\n", alu[i].curso);
printf("Anho:\t%hd\n", alu[i].anho);
}
for(size_t i = 0; i < size; i++)
free(alu[i].nombreApellido);
free(alu);
return 0;
}
Edit
realloc does not need to be wrapped in a different function. But for fun purposes, you can do the following:
void* my_realloc1(void *ptr, int size)
{
ptr = realloc(ptr, size);
if (!ptr) printf("error\n");
return ptr;
}
//usage:
alu = my_realloc1(alu, sizeof(struct listaAlu) * (size + 1));
if (!alu) printf("error\n");
my_realloc1 will work here, however nothing is gained. This is just extra lines of code. It's easier and more clear to use realloc directly and do the necessary error handling.
Another method is to pass a reference:
void my_realloc2(void **ptr, int size)
{
*ptr = realloc(*ptr, size);
}
//usage: (*** Note the address `&` operator ***)
my_realloc2(&alu, sizeof(struct listaAlu) * (size + 1));
if (!alu) printf("error\n");
Again this will work, but it just adds more code.
The function generarCadena seems okay. You could simplify as follows:
char *my_getline()
{
char *buf = NULL;
int in = 0;
size_t size = 0;
while('\n' != (in = getchar()))
{
size++;
buf = realloc(buf, size);
buf[size - 1] = (char)in;
}
size++;
buf = realloc(buf, size);
buf[size - 1] = 0;
return buf;
}
//usage:
printf("Enter name and lastname:\n");
alu[size].nombreApellido = my_getline();
And use scanf for to read 6 characters (because size of cedula is 7)
printf("Enter 6 characters:\n");
scanf("%6s", alu[size].cedula);
alu[size].cedula[6] = '\0';
clear();
To be safe, make sure the input is null terminated, and clear the buffer.
Or you can use fgets as I used in the example. This will read up to 256 characters:
char buf[256];
fgets(buf, sizeof(buf), stdin);
fgets is sometimes easier because you don't need to clear the buffer. But buf includes end of line character \n, you have to remove \n in this case.

Program to reverse a string in C without declaring a char[]

I need to reverse a given string and display it without using the value At[index] notation , I tried the below program using pointers,but it does not print anything for the reverse string,
Please help!
int main()
{
char* name=malloc(256);
printf("\nEnter string\n");
scanf("%s",name);
printf("\nYou entered%s",name);
int i,count;
count=0;
//find the length
while((*name)!='\0')
{
count++;
name++;
}
//pointer now at
printf("\n%p",name);
printf("\nLength is %d",count);
name=name+count;
//pointer now at
printf("\n%p",name);
for(i=0;i<(count);i++)
{
printf("%c",(*name));
name=name-1;
}
return 0;
}
Remove name=name+count; because of the name++ in the precedent loop moved name pointer to the '\0' char;
#include<stdio.h>
#include<stdlib.h>
int main()
{
char* name=malloc(256);
printf("\nEnter string\n");
scanf("%s",name);
printf("\nYou entered%s",name);
int i,count;
count=0;
//find the length and move name pointer
while((*name)!='\0')
{
count++;
name++;
}
//pointer now at
printf("\nPointer is: %p",name);
printf("\nLength is: %d\n",count);
for(i=1;i<=(count);i++)
{
printf("%c",*(name-i));
}
printf("\n");
return 0;
}
OR change the final loop to
for(i=0;i<(count);i++)
{
name--;
printf("%c",*name);
}
Remove name=name+count; and add name--;
Important: scanf(" %s", name); has no bounds checking on the input. If someone enters more than 255 characters into your program, it may give undefined behaviour.
Now, you have the char array you have the count (number of char in the array), and you make name++ (name has the last char offset) then why do you need to bother doing stuffs like this?
name=name+count;
Try this:
#include <stdio.h>
int main()
{
char* name = malloc(256);
// char name[256];
printf("\nEnter string\n");
// scanf("%s", name);
fgets(name, 254, stdin); // carriage return and null character (256-2)
printf("\nYou entered %s", name);
int i, count;
count = 0;
//find the length
while ((*name) != '\0' && (*name) != '\r') {
count++;
name++;
}
//pointer now at
// printf("\n%p", name);
// printf("\nLength is %d", count);
// name = name + count;
//pointer now at
// printf("\n%p", name);
for (i = count; i >= 0; i--) { // starts from last '\0'
printf("%c", (*name));
name = name - 1;
}
return 0;
}
I got the following output:
Enter string rakeb
You entered rakeb
bekar
The easiest way? Just replace them with their syntactic equivalent:
arr[index] // is sugar for ...
arr + index
Then, instead of using two indices to traverse just use pointers. Using this you can actually find a solution pretty easy:
void nreverse(char * str) {
char * forward = str;
char * backward = str + strlen(str) - 1;
while (forward < backward) {
char temp = *forward;
*forward = *backward;
*backward = temp;
++forward;
--backward;
}
}
Try this which will not only print but also reverse string and store it in name.
#include <stdio.h>
int main()
{
char* name = malloc(256);
char *backup1 = *bakcup2 = name;
printf("\nEnter string\n");
fgets(name, 254, stdin); // carriage return and null character (256-2)
printf("\nYou entered %s", name);
while ((*backup1) != '\0' && (*backup1) != '\r') {
backup1++;
}
backup1--; // Because here backup1 was pointing to '\0' or '\r'.
while(backup1 > backup2){
/* Swapping characters */
char temp;
temp = *backup1;
*backup1 = *backup2;
*backup2 = temp;
backup1--;
backup2++;
}
backup1 = name;
while(*backup1 != '\0' && *backup1 != '\r') {
printf("%c", (*backup1));
backup1++;
}
return 0;
}
Please post code that cleanly compiles
The current posted code is missing the required/used header files
the following code
1) includes error checking
2) limits the length of the user supplied string
to avoid a input buffer overflow
3) eliminates certain lines (commented out)
that caused 'name' to point to the wrong location
4) incorporates '\n' at the end of the printf() format strings
so the info will be printed rather than held
in the buffer for stdout
5) at the end, passes the pointer to the malloc'd memory
to the free() function
6) corrects the loop count when printing the
reverse of the input string
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN (256)
int main()
{
char* name=NULL;
char* temp = NULL;
if( NULL ==(name=malloc(256)) )
{ // then malloc failed
perror( "malloc for name[] failed");
exit( EXIT_FAILURE );
}
// implied else, malloc successful
temp = name; // save ptr to malloc'd memory
printf("\nEnter string\n");
if( 1 != scanf("%255s", name) )
{ // then scanf failed
perror( "scanf for name failed");
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("\nYou entered: %s\n",name);
int i,count;
count=0;
//find the length
while((*name)!='\0')
{
count++;
name++;
}
//pointer now at
printf("\nAddress of last char in name[]: %p\n",name);
printf("\nLength is %d\n",count);
//name=name+count;
//pointer now at
//printf("\n%p",name);
for(i=0;i<=count;i++)
{
printf("%c",(*name));
name--;
}
printf( "\n" );
free(temp);
return 0;
} // end function: main

filling a Char array with scanf in C

How can I fill an empty Char Array with keyboard?
something like
char a_string[];
while("if not Q")
{
printf("Enter a number: ");
scanf("%c", a_string);
}
I know this is wrong
I just want to know how to give values to my a_string[], without limiting the size.
so the size will vary depend on how many keys i'm gonna enter from keyboard.
Thanks!
If you will know at the start of runtime how many keys you'll enter, you can have it ask first for the number of keys and then for the individual characters, as in the untested snippet below.
Otherwise, you have to set some real-world maximum (e.g. 10000) that will never be reached, or, if that's not possible, set a per-array maximum and make provisions for rollover into a new array. That last option really is the same (eventually bounded by memory) but gives you a larger maximum.
char *mychars;
int numchars;
printf("Please enter the total number of characters:\n");
if (scanf("%d", &numchars) == NULL) {
printf("couldn't read the input; exiting\n");
exit(EXIT_FAILURE);
}
if (numchars <= 0) {
printf("this input must be positive; exiting\n");
exit(EXIT_FAILURE);
}
mychars = (char *) malloc (numchars * sizeof(char));
int current_pos = 0;
printf("Enter a digit and hit return:\n");
while (scanf("%c", &mychars[current_pos]) != NULL && current_pos < numchars) {
current_pos++;
printf("Enter a digit and hit return:\n");
}
Try this:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *string = NULL;
char *newstring = NULL;
char c = '\0';
unsigned int count = 0;
while(c != 'Q'){
c = getc(stdin);
if(string == NULL){
string = (char *) malloc(sizeof(char)); // remember to include stdlib.h
string[0] = c;
}
else{
newstring = (char *) realloc(string, sizeof(char)*count);
string = newstring;
string[count] = c;
}
count++;
}
string[count-1] = '\0'; // remove the Q character
fprintf(stderr,"here you are: %s",string);
free(string); // remember this!
return 0;
}
Repetitive calls to realloc() will meet the need.
Double realloc() size as needed to avoid O(n) calls.
char *GetQLessString(void) {
size_t size_alloc = 1;
size_t size_used = size_alloc;
char *a_string = malloc(size_alloc);
if (a_string == NULL) {
return NULL; // Out of memory
}
char ch;
while(scanf("%c", &ch) == 1 && (ch != 'Q')) {
size_used++;
if (size_used > size_alloc) {
if (size_alloc > SIZE_MAX/2) {
free(a_string);
return NULL; // Too big - been typing a long time
}
size_alloc *= 2;
char *new_str = realloc(a_string, size_alloc);
if (new_str == NULL) {
free(a_string);
return NULL; // Out of memory
}
a_string = new_str;
}
a_string[size_used - 2] = ch;
}
a_string[size_used - 1] = '\0';
return a_string;
}
Code could do a final realloc(a_string, size_used) to trim excess memory allocation.
Calling routine needs to call free() when done with the buffer.
The following would be cleaner.
int ch;
while((ch = fgetc(stdin)) != EOF && (ch != 'Q')) {

Resources