Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading in a variable length string user input in C

Tags:

c

string

input

I am trying to read in a variable length user input and perform some operation (like searching for a sub string within a string).

The issue is that I am not aware how large my strings (it is quite possible that the text can be 3000-4000 characters) can be.

I am attaching the sample code which I have tried and the output:

char t[],p[];
int main(int argc, char** argv) {
    fflush(stdin);
    printf(" enter a string\n");
    scanf("%s",t);

    printf(" enter a pattern\n");
    scanf("%s",p);

    int m=strlen(t);
    int n =strlen(p);
    printf(" text is %s %d  pattrn is %s %d \n",t,m,p,n);
    return (EXIT_SUCCESS);
}

and the output is :

enter a string
bhavya
enter a pattern
av
text is bav 3  pattrn is av 2
like image 289
bhavs Avatar asked Oct 06 '11 09:10

bhavs


2 Answers

Please don't ever use unsafe things like scanf("%s") or my personal non-favourite, gets() - there's no way to prevent buffer overflows for things like that.

You can use a safer input method such as:

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

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

You can then set the maximum size and it will detect if too much data has been entered on the line, flushing the rest of the line as well so it doesn't affect your next input operation.

You can test it with something like:

// Test program for getLine().

int main (void) {
    int rc;
    char buff[10];

    rc = getLine ("Enter string> ", buff, sizeof(buff));
    if (rc == NO_INPUT) {
        // Extra NL since my system doesn't output that on EOF.
        printf ("\nNo input\n");
        return 1;
    }

    if (rc == TOO_LONG) {
        printf ("Input too long [%s]\n", buff);
        return 1;
    }

    printf ("OK [%s]\n", buff);

    return 0;
}
like image 162
paxdiablo Avatar answered Sep 21 '22 01:09

paxdiablo


In practice you shouldn't bother too much to be precise. Give yourself some slack to have some memory on the stack and operate on this. Once you want to pass the data further, you can use strdup(buffer) and have it on the heap. Know your limits. :-)

int main(int argc, char** argv) {
    char text[4096]; 
    char pattern[4096]; 
    fflush(stdin);
    printf(" enter a string\n");
    fgets(text, sizeof(text), stdin);

    printf(" enter a pattern\n");
    fgets(pattern, sizeof(pattern), stdin);

    int m=strlen(text);
    int n =strlen(pattern);
    printf(" text is %s %d  pattrn is %s %d \n",text,m,pattern,n);
    return (EXIT_SUCCESS);
}
like image 39
RushPL Avatar answered Sep 22 '22 01:09

RushPL