How to handle buffer error while validating user input - c

I need to read in user input as an integer to pass it to my other function. If I use my validation (code below), it crashes after 4 bad inputs. I'm not completely sure if this is even a buffer error or not. But I also didn't find a proper way to validate my input and handle the errors. I didn't use scanf(%d) on purpose because I wanted to dodge the warning CLion is giving me when using it. I hope someone here can explain to me why my code is crashing after 4 bad inputs and how to fix it, or show me an alternative way.
char *userInput = malloc(100);
long amountOfPlayers;
//Todo: More Validation needed, bufferoverflow
for (int i = 0; i < sizeof(userInput) / sizeof(*userInput); i++) {
char *end;
printf("Please enter the amount of players: ");
scanf("%s", userInput);
amountOfPlayers = strtol(userInput, &end, 10);
if (end == userInput) {
printf("wasn't a number\n");
}
else if (end[0] != '\0') {
printf("trailing characters after number %ld: %s\n", amountOfPlayers, end);
}
else
return init_playerList(amountOfPlayers);
}

userInput is a pointer, not an array, so sizeof(userInput) returns the size of a pointer, typically 4 bytes. sizeof(*userInput) is sizeof(char), which is 1. So sizeof(userInput) / sizeof(*userInput) is 4, which means your for loop only executes 4 times. See How to find the 'sizeof' (a pointer pointing to an array)?
There's no need for a for loop, just use while (true). You're not doing anything that iterates over the elements of userInput, it's just the buffer.
There's also no reason to allocate it with malloc(), you can simply declare:
char userInput[100];
You have a memory leak because you never free(userInput) before returning from the function. But if you declare it as an array this is not necessary.
TO prevent buffer overflow you should use:
scanf("%100s", userInput);

sizeof(userInput) / sizeof(*userInput) won't return the number of elements, because userInput is a pointer, not an array. This only works for pure arrays. In case of pointer is always return the same value: size of a pointer divided by the size of the object.
int size = 100;
char *userInput = malloc(size);
if(userInput == NULL)
{
// error handling
}
for (int i = 0; i < n; i++) {
....
}
would be correct.

Related

C scanf - unknown array size

I want to read values (float) into an array but I don't know number of values.
My input is this
Enter values: 1.24 4.25 1.87 3.45 .... etc
How can I load this input to an array? I know that input ends when enterring 0 or EOF.
while(0 or EOF){
scanf("%f", &variable[i])
i++;
}
Thank you.
You can dynamically allocate the array and then reallocate the memory for it when the previously allocated buffer is full. Note that the conversion specifier %f in the format string of scanf reads and discards the leading whitespace characters. From the man page of scanf -
scanf returns the number of items successfully matched and assigned
which can be fewer than provided for, or even zero in the event of an
early matching failure. The value EOF is returned if the end of input
is reached before either the first successful conversion or a matching
failure occurs.
This means that scanf will return EOF only when it encounters EOF as the first input when it is called because EOF must be preceded with a newline '\n' else it won't work (depending on the OS). Here's a small program to demonstrate how you can do it.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t len = 4;
float *buf = malloc(len * sizeof *buf);
if(buf == NULL) { // check for NULL
printf("Not enough memory to allocate.\n");
return 1;
}
size_t i = 0;
float *temp; // to save buf in case realloc fails
// read until EOF or matching failure occurs
// signal the end of input(EOF) by pressing Ctrl+D on *nix
// and Ctrl+Z on Windows systems
while(scanf("%f", buf+i) == 1) {
i++;
if(i == len) { // buf is full
temp = buf;
len *= 2;
buf = realloc(buf, len * sizeof *buf); // reallocate buf
if(buf == NULL) {
printf("Not enough memory to reallocate.\n");
buf = temp;
break;
}
}
}
if(i == 0) {
printf("No input read\n");
return 1;
}
// process buf
for(size_t j = 0; j < i; j++) {
printf("%.2f ", buf[j]);
// do stuff with buff[j]
}
free(buf);
buf = NULL;
return 0;
}
I guess your actual concern is the unknown number of floats that user is going to input. You can use pointer to float, do malloc for some predefined size, if your limit has reached while taking an input then do a realloc to increase the memory. You need to take care of previously accepted data while doing a reaccloc.
You need a dynamic allocation of your array since you don't know its size at compile time.
// INITIAL_SIZE can be the average expected size of your array
#define INITIAL_SIZE 4
// size will track the current maximum size of youe array.
size_t size = INITIAL_SIZE;
// dynamic allocation for variable
float* variable = malloc(sizeof(float)*size);
// check that the allocation happened correctly
assert(variable != NULL);
// i contains the current actual size of your array
int i = 0;
while (0 or EOF) {
if (i >= size) {
// if the array is getting bigger than its max size, resize it.
size *= 2;
// This will reallocate enough memory for variable.
variable = realloc(variable, sizeof(float)*size);
// check that the allocation happened correctly;
assert(variable != NULL);
// (NB: It IS important to affect variable to the result of
// realloc, you can't simply realloc as in some cases the
// original pointer will become invalid!)
}
scanf("%f", &variable[i])
i++;
}
As an aside, please note that variable is not a wonderful variable name. Use a name describing what your variable is used for.
EDIT: corrected the size in realloc to alloc size*2 floats and avoid it break horribly, as unwind pointed out.
i = 0;
while(scanf("%f", &variable[i])!=-1)
{
i++;
}
scanf returns -1 when it tries to read after EOF.

Displaying the contents of a dynamic array backwards

So the program is supposed to do the following:
Ask the user to enter strings (max length of the string being 250), and once the user enters nothing (so basically hitting 'enter'), the program stops taking input and proceeds to display every string the user has input backwards.
Here's my code - everything works except I can't enter the while loop at the bottom.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char userInput[250];
char *newSpace;
char *array;
int stringLength;
int inputElems = 0;
//Reset startingPtr back to where 'array' begins
char *startingPtr = array - inputElems;
// Sets endPtr to the last input element in the array
char *endPtr = startingPtr + inputElems;
do
{
puts("Please enter a string!");
// Gets input from user
fgets(userInput, 250, stdin);
// Finds out the number of characters the user entered
// + 1 to make room for the null character
stringLength = strlen(userInput) + 1;
// Allocate memory with the needed space
newSpace = malloc(stringLength);
// If malloc didn't allocate memory, display error
if (NULL == newSpace)
{
puts("Error!");
}
// Copy user input into array
strcpy(newSpace, userInput);
// Save input into array
array = newSpace;
// For testing purposes only, this line will be deleted once I can access the array
//puts("Here's what you wrote");
//printf("%s", array);
// Increase array
array++;
// Increase number of times user has input something
inputElems++;
} while(stringLength != 2);
//puts("Testing outside");
while (endPtr > startingPtr)
{
//puts("Testing inside");
--endPtr;
printf("%s", *endPtr);
}
free(newSpace);
}
Your while loop body is never executed because you never modify endPtr and startingPtr throughout the program's lifetime, they both point to the same location. Thus, endPtr > startingPtr will never be true.
Also, array++ does not work the way you expect: array points to the first character of what the user wrote, and array++ just moves it forward to the next character. I think you want an array of char *. Thus, change char *array; to char *array[250]; (assuming that the user can enter at most 250 sentences).
And of course, since you can't increment an array, because an array is not a modifiable l-value, you must also keep a count for the last index written. But I see that you already have inputElems, that should be enough. Here's the modified code:
int main()
{
char userInput[250];
char *newSpace;
char *array[250];
int stringLength;
int i;
int inputElems = 0;
do
{
puts("Please enter a string!");
// Gets input from user
fgets(userInput, 250, stdin);
// Finds out the number of characters the user entered
// + 1 to make room for the null character
stringLength = strlen(userInput) + 1;
// Allocate memory with the needed space
newSpace = malloc(stringLength);
// If malloc didn't allocate memory, display error
if (NULL == newSpace)
{
puts("Error!");
}
// Copy user input into array
strcpy(newSpace, userInput);
// Save input into array
array[inputElems] = newSpace;
// For testing purposes only, this line will be deleted once I can access the array
//puts("Here's what you wrote");
//printf("%s", array);
// Increase number of times user has input something
inputElems++;
} while(stringLength != 2);
//puts("Testing outside");
for (i = inputElems-1; i >= 0; i++)
{
//puts("Testing inside");
printf("%s", array[i]);
free(array[i]);
}
return 0;
}
Note the updated loop in the end of the code. It goes through the array from end to beginning. Note that I changed the place where you call free(). Since we're allocating memory inside a loop, for each position in array, we must also free() every position, thus this must also be made inside a loop.
Ok. you need an array of pointers like: char *arr[10];
You can store here 10 strings from arr[0] to arr[9]. (Well not directly 10 strings, but the pointers to them)
arr[0] = (char*)malloc(sizeof(char * length_of_string));
strncpy(arr[0], your_string, length_of_string);
When just print arr[9] to arr[0].
mfg

Tokenizing user input in C (store in **arg)?

I'm attempting to write a simple shell like interface, that takes in a users input (by char) and stores it via a pointer to a pointer* (exactly how argv works). Here's my code:
char input[100];
char **argvInput;
char ch;
int charLoop = 0;
int wordCount = 0;
argvInput = malloc(25 * sizeof(char *));
while((ch = getc(stdin))) {
if ((ch == ' ' || ch == '\n') && charLoop != 0) {
input[charLoop] = '\0';
argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char));
argvInput[wordCount] = input;
charLoop = 0;
wordCount++;
if (ch == '\n') {
break;
}
} else if (ch != ' ' && ch != '\n') {
input[charLoop] = ch;
charLoop++;
} else {
break;
}
}
If I loop through argvInput via:
int i = 0;
for (i = 0; i < wordCount; i++)
printf("Word %i: %s\n", i, argvInput[i]);
All of the values of argvInput[i] are whatever the last input assignment was. So if I type:
"happy days are coming soon", the output of the loop is:
Word 0: soon
Word 1: soon
Word 2: soon
Word 3: soon
Word 4: soon
I'm at a loss. Clearly each loop is overwriting the previous value, but I'm staring at the screen, unable to figure out why...
This line is your bane:
argvInput[wordCount] = input;
Doesn't matter that you allocate new space, if you're going to replace the pointer to it with another one (i.e. input).
Rather, use strncpy to extract parts of the input into argvInput[wordCount].
argvInput[wordCount] = input; is only making the pointer of argvInput[wordCount] point to the memory of input instead of copy the content of input into the new allocated memory. You should use memcpy or strcpy to correct your program.
After the pointer assignment the memory status looks like the image below. The memory allocated by malloc((charLoop + 1) * sizeof(char));, which are the grey ones in the graph, could not be accessed by your program anymore and this will lead to some memory leak issue. Please take care of that.
I suggest printing your argvInput pointers with %p, instead of %s, to identify this problem: printf("Word %i: %p\n", i, (void *) argvInput[i]);
What do you notice about the values it prints? How does this differ from the behaviour of argv? Try printing the pointers of argv: for (size_t x = 0; x < argc; x++) { printf("Word %zu: %p\n", x, (void *) argv[x]); }
Now that you've observed the problem, explaining it might become easier.
This code allocates memory, and stores a pointer to that memory in argvInput[wordCount]: argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char)); (by the way, sizeof char is always 1 in C, so you're multiplying by 1 unnecessarily).
This code replaces that pointer to allocated memory with a pointer to input: argvInput[wordCount] = input; ... Hence, all of your items contain a pointer to the same array: input, and your allocated memory leaks because you lose reference to it. Clearly, this is the problematic line; It doesn't do what you initially thought it does.
It has been suggested that you replace your malloc call with a strdup call, and remove the problematic line. I don't like this suggestion, because strdup isn't in the C standard, and so it isn't required to exist.
strncpy will work, but it's unnecessarily complex. strcpy is guaranteed to work just as well because the destination array is allocated to be large enough to store the string. Hence, I recommend replacing the problematic line with strcpy(argvInput[wordCount], input);.
Another option that hasn't been explained in detail is strtok. It seems this is best left unexplored for now, because it would require too much modification to your code.
I have a bone to pick with this code: char ch; ch = getc(stdin); is wrong. getc returns an int for a reason: Any successful character read will be returned in the form of an unsigned char value, which can't possibly be negative. If getc encounters EOF or an error, it'll return a negative value. Once you assign the return value to ch, how do you differentiate between an error and a success?
Have you given any thought as to what happens if the first character is ' '? Currently, your code would break out of the loop. This seems like a bug, if your code is to mimic common argv parsing behaviours. Adapting this code to solve your problem might be a good idea:
for (int c = getc(stdin); c >= 0; c = getc(stdin)) {
if (c == '\n') {
/* Terminate your argv array and break out of the loop */
}
else if (c != ' ') {
/* Copy c into input */
}
else if (charLoop != 0) {
/* Allocate argvInput[wordCount] and copy input into it,
* reset charLoop and increment wordCount */
}
}

realloc not working for 2-D pointer array

In the following code, I ask the user to give me some strings. I make a 2-D pointer char array, so that I read the input with pointer string which points to the start of a string of length 50. My problem is that I keep crashing after the input of the first string.. and I assume that my problem has to do with the realloc. I am not used to it.. can you please help to figure out what is happening?? I tried to debug with netbeans, but didn't manage to see anything interesting, since it doesn't give feedback for the new addresses made from realloc!!
Here is the code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *str,**string,buffer[50],temp[2];
int i,j,q,size,counter;
size=10;
string=(char**) calloc(size,sizeof(char*));
for (i=0; i<size; i++) string[i]=(char*) malloc(50*sizeof(char));
printf("\nGimme strings, terminate input with x");
i=0;
gets(string[i]);
temp[0]=120;//x
temp[1]='\0';
size=0;
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
return 0;
}
I want to make the table of pointers bigger with this realloc.
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
After you call realloc to enlarge string, the new portion contains no valid pointers. So when you call gets, you're passing it a pointer you failed to initialize.
Also, that size=0; is totally broken.
realloc does not initialize the allocated memory with zeros, in addition you forgot to initialize the newly allocated string pointers.
Consider to move up i++ and size++ within the while loop.
Code Review
initialize all your variables
char *str = NULL,**string = NULL,buffer[50] = {0},temp[2] = {0};
int i = 0,j = 0,q = 0,size = 10,counter = 0;
do not cast what is returned from malloc/calloc and use {} when possible for clarity
string=calloc(size,sizeof(char*));
for (i=0; i<size; i++)
{
string[i]=malloc(50*sizeof(char));
}
When reading from the keyboard do not use gets, use fgets() since you can specify the max size to read.
printf("\nGimme strings, terminate input with x");
char input[256];
fgets(input,sizeof(input),stdin); // another varname, will explain below
With newer compilers you can declare variables where you need them instead of decl at top of function.
char temp={'x','\0'}; // 120;//x
setting size=0 here seems a bit strange
size=0;
it is better to keep what the user inputs in a separate buffer (input)
then if it is not "x" copy it into your string array so instead of
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
e.g.
while (fgets(input,sizeof(input),stdin) != NULL && input[0] != 'x')
{
string[i] = calloc(1,strlen(input)+1); // add a byte for \0
strncpy(string[i],input,strlen(input)-1); // not copying ending \n
if ( ++i == size ) // a new chunk needed
{
char *newstring = realloc((size + 10)*sizeof(char*), string );
if ( newstring != NULL )
{
string = newstring;
size += 10;
}
}
}

C Language: Newb translating code from javascript to C, code includes malloc, strncpy, pointers

I am converting (from javascript) a program that will take a string of variable length (but always under 100 char) and return the data contained in the string in individual variables. This is the first portion of my code, and obviously, I am new to C and programming in general. This code is for the first section of the code, but learning how to properly code this would give me the know how to code the rest.
I need:
the first 4 digits to be stored as 'stringID'
the 5th digit to be stored as 'myindicator'
the 6th through (indicator + 6) digits to be stored as 'var1'
Example input:
'12345678901234567890123'
Example output:
stringID = 1234
myindicator = 5
var1 = 67890123456
When I run the program, it returns 'String ID: H>a' and then the program crashes. Any help would be appreciated. No, this is not homework.
int main()
{
char mystring[100];
char *stringID;
int nep;
int *myindicator;
char *var1;
nep = 0;
printf("Please enter your CODE\n");
scanf("%s", &mystring);
stringID = (char *)malloc(4 * sizeof(char));
if(NULL != stringID)
{
strncpy(stringID, mystring, 4);
stringID[4] = '\0';
free(stringID);
nep = nep +4;
printf("stringID: %s\n",myindicator);
}
if(NULL != myindicator)
{
strncpy(myindicator, (mystring+nep, 1);
nep++;
myindicator = *myindicator - '0';
printf("Indicator : %d\n",myindicator);
}
var1 = (char *)malloc((nep + 6) * sizeof(char));
if(NULL != var1)
{
strncpy(var1, mystring+nep, (myindicator+nep+6));
var1[myindicator+nep+6] = '\0';
free(var1);
printf("Var 1: %s", var1);
nep = nep +myindicator+6;
}
getchar();
return 0;
}
I fixed something, find it in the comments. But you need to check a C language manual...!
int main()
{
char mystring[100];
char *stringID;
int nep;
// Changed to integer, not pointer to int.
int myindicator;
char *var1;
nep = 0;
printf("Please enter your CODE\n");
/*
This scanf is a bad idea for the same reason for which, below, we take
care to allocate memory enough for whatever we have to do.
Should someone input 250 characters in a buffer of size 100, those 150
extra characters would wreak havoc and possibly endanger the system.
*/
// scanf("%s", &mystring);
fgets(mystring, sizeof(mystring)-1, stdin);
// fgets will read at most "sizeof(mystring)-1", that is, 99 bytes,
// from "stdin" (STanDard INput), the same as scanf. But it will halt
// when reaching the limit given. It's up to us to give a "real" limit
// (nothing stops you from saying 15000 -- even if the true value is 100).
// C strings are made of characters, terminated by a zero byte.
// So you need 5 here, to store 4 characters
stringID = (char *)malloc(5 * sizeof(char));
if (NULL == stringID)
{
// Serious out of memory error: no sense going on.
// fprintf(stderr, "Out of memory\n");
abort();
}
strncpy(stringID, mystring, 4);
stringID[4] = '\0';
printf("ID: %s\n", stringID);
free(stringID);
nep = nep + 4;
printf("NEP: %d\n", nep);
// Now we want to decode the fifth digit.
// I use '0' as character. So if the fifth digit is '0', '0'-'0' will give 0
// and if it is '9', '9'-'0' will give 9 (the number).
// The trick does not work with more than one digit, of course.
myindicator = mystring[nep] - '0';
// Had I wanted to read 3 digits, I would have had to copy them into a
// temporary buffer, add a zero in the fourth position, then run atol()
// on the resulting buffer: atol("12345\0" /* A STRING */) = 12345 /* A NUMBER */;
printf("VLI : %d\n", myindicator);
// Copy "myindicator" bytes, so alloc myindicator+1 chars
var1 = (char *)malloc((myindicator + 1) * sizeof(char));
// Check that var1 is not null and abort if it is
if (NULL == var1)
abort();
strncpy(var1, mystring + 6, myindicator);
var1[myindicator+1] = '\0';
// Moved this printf before the free. See why below.
printf("Prefix : %s\n", var1);
// NEVER use a variable after you freed it!!!
// it might APPEAR to work, but will stab you in the back the first chance it gets.
// Good if paranoid habit: null a var as soon as you've freed it.
free(var1); var1 = NULL;
getchar();
return 0;
}
why are you freeing your array's ? you are referencing them after you have freed them from heap.
Your code will segfault in these places :
where did you allocated myindicator?
strncpy(myindicator, (mystring+nep, 1); // it will segfault here.
free(var1);
printf("Prefix : %s", var1); // again segfault
Again here
strncpy(var1, mystring+nep, (myindicator+nep+6)) //where is your mystring?
taking string input by scanf() is horrible horrible idea. use buffered IO like fgets().
You are exposing your mystring to buffer overflow. who is preventing the user from inputting a 120 byte string? i can write your stack with careful jump instruction to my malicious code.

Resources