Getting unlimited input in C?

So I'm trying to program a function which allows the user to enter an unlimited amount of chars. For example this:

char string[100]

limits the input to 100 characters.

The code i have so far is:

#include<stdio.h>

char* uinput(){
    char *string, *current;
    int counter = 0;
    string = (char *) malloc(10 * sizeof(char));
    do{
        realloc(string, counter * sizeof(char));
        current = string + counter;
        *current = getchar();
        counter++;
    }while(*current != '\n');
    return string;
}

int main(){
    char *s;
    s = uinput();
    printf("\nYou entered: %s", *s);
    return 0;
}

I'm new to pointers, so I'm not sure why this doesn't work(Program crashes). What I'm trying to do is keep reading a character and keep relocating the string pointer so the amount of bytes keeps increasing until the user presses enter ('\n').

Thanks ~Raf

Upvotes: 0

Views: 3882

Answers (5)

The approach is sane, but there are minor details that are wrong. If you compile with warnings enabled, you'd notice that you're missing <stdlib.h>; also you're giving the first character to printf instead of the pointer to the buffer.

Then there is the obvious bug that your size is reset to 0, and you're casting the return value of malloc, using char to store the result of getchar() which is also wrong because you cannot check against EOF. You're not saving the realloced pointer; and you're not terminating the string properly. On minor detail, you'd want to double the size of buffer in each realloc, because realloc needs to potentially copy the whole line, so it becomes slower and slower over time as the line grows in length.

Thus we get:

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

char* uinput() {
    char *string;
    // number of characters in the buffer
    size_t counter = 0;

    // size of allocated buffer
    size_t allocated = 16;
       
    int c;
    string = malloc(allocated);  // sizeof(char) is 1
    do {
        c = getchar();
        if (c == EOF) {
            break;
        }
        // if our buffer is too small, double the allocation 
        if (counter + 2 <= allocated) {
            size_t new_size = allocated * 2;
            char *new_buffer = realloc(string, new_size);
            if (! new_buffer) {
                // out of memory? try smaller increment
                new_size = allocated + 16;
                new_buffer = realloc(string, new_size);
                if (! new_buffer) {
                    // really out of memory: free old block
                    free(string);
                    return NULL;
                }
            }
            allocated = new_size;
            string = new_buffer;
        }
        // store the character
        string[counter++] = c;
    } while (c != '\n');

    // terminate the buffer properly
    string[counter - 1] = '\0';
    return string;
}

int main() {
    char *s = uinput();
    if (!s) {
        // possibly out of memory in uinput
        perror("Error reading input");
        exit(EXIT_FAILURE);
    }
    printf("\nYou entered: %s", s);
    free(s);
    return EXIT_SUCCESS;
}

Upvotes: 1

Daomtthuan
Daomtthuan

Reputation: 19

use getchar, malloc and realloc for reading the unlimited input string

Declare String type, you can also use char *

// String type
typedef char *String;

I write this function for joining the char in the end of string

/**
 * Join the Char into end of String
 *
 * @param string - String
 * @param c - joined char
 */
void String_joinChar(String *string, const char c)
{
  const size_t length = strlen(*string);
  (*string) = (String)realloc((*string), sizeof(char) * (length + 2));
  (*string)[length] = c;
  (*string)[length + 1] = '\0';
}

This function for inputting string, which read the char from keyboard by using getchar and join it in the end of current string.

/**
 * Input String
 *
 * @return Inputed String
 */
String String_input()
{
  String string = (String)malloc(sizeof(char));
  strcpy(string, "");

  char cursor;
  fflush(stdin);
  while ((cursor = getchar()) != '\n' && cursor != EOF)
  {
    String_joinChar(&string, cursor);
  }

  return string;
}

Cause of using char *, malloc and realloc, we must free it

/**
 * Destroy String
 *
 * @param string - Destroyed String
 */
void String_destroy(String string)
{
  free(string);
}

And now we just use it !!

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

int main()
{
  String string = String_input();
  printf("\n%s\n", string);
  String_destroy(string);
  return 0;
}

Hope useful to you!

Upvotes: 0

Dave the Sax
Dave the Sax

Reputation: 328

Another approach is to use fgets(), which gets a string into a sized buffer from the input stream; if it has the complete input then the string ends with \n; if it doesn't then it doesn't. So you can loop calling fgets until there is an EOL character at the end, then depending on what your program does with the input you can decide whether to keep realloc-ing or to process the input a bit at a time.

Upvotes: 0

Michi
Michi

Reputation: 5307

You could try something like the following:

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

struct person{
    char *name;
}pers;

void addMem(void);

int main(void){
    addMem();

    printf("\nYour name is:>  %s\n",pers.name);
    free(pers.name);
    pers.name = NULL;
    return 0;
}

void addMem(void){
    unsigned int length = 6;
    size_t newLength = 0;
    unsigned int newSize = 0;
    unsigned int i =0;
    char *name;
    int c;

    name = malloc(length);
    if(name == NULL){
        exit(1);
    }
    newSize = length;

    printf("Enter your name:>  ");

    while ((c = getchar()) != '\n' && c!=EOF){
        name[i++]=(char)c;

        if(i == newSize){
            newSize = i+length;
            name = realloc(name, newSize);
        }
    }

    name[i] = '\0';

    newLength = strlen(name)+1;
    pers.name = malloc(newLength);

    memcpy(pers.name, name, newLength);

    free(name);
    name = NULL;
}

Upvotes: 0

knightrider
knightrider

Reputation: 2153

Ok I think this is the problem

you are re-allocing

realloc(string, counter * sizeof(char));

The what will be the size of string in first iteration? It will be 0.

Now you are writing to a pointer which has 0 bytes allocated and hence segfault.

Changing it to a while loop can help to fix it. You can also change the initial value of counter to fix it

Upvotes: 2

Related Questions