Reading numbers - c

Huge thanks to everyone that answered , i have realised that i suck a lot at this, i will take every answer into consideration and hopefully i will manage to compile something that is working

Some remarks:
Allocating 500 MB just in case doesn't seem like a good idea. A better approach would be to allocate a small amount of memory first, if it's not enough then allocate 2 times bigger memory, etc (this would work if you read the number on per-character basis).
Important: right after every (re)allocation, you have to check whether your malloc call succeeded (i.e. what it returns is not NULL), otherwise you cannot go any further.
what the first getchar() is for?
instead of using gets(), you could try to read the characters one-by-one, until you encounter something that is not a number, at which point you can assume that the number input has finished (that is the simplest way, obviously one can process user input differently).
adding '\0' for something that was read with gets() is not needed, afaik (for something that would be read character-by-character, that would make sense).
Last but not least, you should also take care of actually freeing the allocated memory (i.e. calling free() after you are done with num). Not doing so results in a memory leak.
(Update) printf("%c",num[0]); will only print the first character of the string num. If you want to print out the whole string, you should call printf("%s",num);

Well, there are quite a few problems with this code, none that necessarily have to do with reading big numbers. But you're still learning, so here we go. In order in which they appear in the code:
(Not really an error, but also not recommended): Casting the result of malloc is unnecessary, as outlined in this answer.
As the other answer states: allocating 500MB is probably way overkill, if you really need this much you can always add more, but you may want to start out with less (5KB, for example).
You should add a new-line at the end of your puts, or the output may end up in places where you don't expect it (i.e. much later).
(This is an error) Don't ever use gets: this page explains why.
You're checking if(num == NULL) after you've already used it (presumably to check if gets failed, but it will return NULL on failure, the num pointer itself won't be changed). You want to move this check up to right after the malloc.
After your NULL-check for num your code happily continues after the if, you'll want to add a return or exit inside the if's body.
There is a syntax error with your very last printf: you forgot the closing ].
When you decide to use fgets to get the user input, you can check if the last character in the string is a new-line. If it isn't then that means it couldn't fit the entire input into the string, so you will need to fgets some more. When the last character is a new-line you might want to remove that (use num[len]='\0'; trick that isn't necessary for gets, but is for fgets).
Instead of increasing the size of your buffer by just 1, you should grow it by a bit more than that: a common used value is to just double the current size. malloc, calloc and realloc are fairly expensive system-calls (performance-wise) and since you don't seem too fussed about memory-usage it can save a lot of time keeping these calls to a minimum.
An example of these recommendations:
size_t bufferSize = 5000, // start with 5K
inputLength = 0;
char * buffer = malloc(bufferSize);
if(buffer == NULL){
perror("No memory!");
exit(-1);
}
while(fgets(buffer, bufferSize, stdin) != NULL){
inputLength = strlen(buffer);
if(buffer[inputLength] != '\n'){ // last character was not a new-line
bufferSize *= 2; // double the buffer in size
char * tmp = realloc(buffer, bufferSize);
if(tmp == NULL){
perror("No memory!");
free(buffer);
exit(-1);
}
// reallocating didn't fail: continue with grown buffer
buffer = tmp;
}else{
break; // last character was a new-line: were done reading
}
}
Beware of bugs in the above code; I have only proved it correct, not tried it.
Finally, instead of re-inventing the wheel, you may want to take a look at the GNU Multiple Precision library which is specifically made for handling big numbers. If anything you can use it for inspiration.

This is how you could go about reading some really big numbers in. I have decided on your behalf that a 127 digit number is really big.
#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 128
int main()
{
int n, number, len;
char *num1 = malloc(BUFSIZE * sizeof (char));
if(num1==NULL){
puts("Not enough memory");
return 1;
}
char *num2 = malloc(BUFSIZE * sizeof (char));
if(num2==NULL){
puts("Not enough memory");
return 1;
}
puts("Please enter your first number");
fgets(num1, BUFSIZE, stdin);
puts("Please enter your second number");
fgets(num2, BUFSIZE, stdin);
printf("Your first number is: %s\n", num1);
printf("Your second number is: %s\n", num2);
free(num1);
free(num2);
return 0;
}
This should serve as a starting point for you.

Related

Have to hit enter twice with fgets() in C?

Good Morning, I'm having an issue with some C code where I am forced to hit enter twice each time input is entered if the length of the input is less than the size of 'guess'.
If the length of the input is longer than guess, I only hit enter once, and it functions normally.
I'm not sure what the issue is here, but I provided the function in question that I believe is the source of the problem along with the caller function and main just for context.
Output:
Guess a number: 5555555555
Invalid guess.
Guess a number: 55555555555
Invalid guess.
Guess a number: 555
Invalid guess.
Guess a number:
Invalid guess.
Guess a number: 5555
When I remove the line:
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
and I extend past the size of the buffer, I receive this output:
Guess a number: 5555555555555555555555555555555555
Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Function in Question
char * get_input(char * guess)
{
print_message("guess"); // Prompt user to input a guess
fgets(guess, sizeof (guess), stdin);
if(feof(stdin))
{
printf("error");
exit(EXIT_FAILURE);
}
int ch = 0;
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
guess[strlen(guess)-1] = '\0'; // Erase new line character
return guess;
}
Caller Function
int make_guess(int *v_guess_count)
{
int result = 0;
bool valid = false;
char guess[10] = {'\0'}; // Buffer to store the guess
do
{
get_input(guess); // Get the input
if(is_valid(guess)) // Check if the input is valid
{
valid = true;
*v_guess_count += 1;
}
}
while (! valid); // Keep asking for input until guess is valid
result = assign_value(guess); // Assign the guess
return result;
}
Main
int main(int argc, char * argv[])
{
int red = 0;
int white = 0;
int v_guess_count = 0;
int target = get_target();
bool game_won = false;
while(game_won == false)
{
red, white = 0; // Reset to zero after each guess
int guess = make_guess(&v_guess_count); // Make a guess. If it's valid, assign it.
printf("guess is: %d\n", guess);
compare(guess, target, &red, &white); // Check the guess with the target number.
print_hints(&red, &white);
if (red == 4)
{
game_won = true;
}
}
printf("You win! It took you %d guesses.\n", v_guess_count);
return 0;
}
You have two somewhat-related problems.
One. In your function
char * get_input(char * guess)
your line
fgets(guess, sizeof (guess), stdin);
does not do what you think it does. You want to tell fgets how big the buffer is, that is, how much memory is pointed to by guess for fgets to read into. But in function get_input, parameter guess is a pointer, so sizeof(guess) is going to be the size of that pointer, not the size of the array it points to. That is, you're going to get a size of probably 4 or 8, not the 10 that array guess up in make_guess is declared as.
To fix this, change your input function to
char * get_input(char * guess, int guess_size)
and change the call in make_guess to
get_input(guess, sizeof(guess));
For more on this point, see this question and also this answer.
Two. Your array guess for reading the user's guess is too small. Instead of making it size 10, make it size 500 or something. That way it will "never" overflow. Don't worry that you're wasting memory by doing that — memory is cheap.
The reason for making the input buffer huge is this: If you make the buffer small, you have to worry about the case that the user might type a too-long line and that fgets might not be able to read all of it. If you make the buffer huge, on the other hand, you can declare that the problem "won't happen" and that you therefore don't have to worry about it. And the reason you'd like to not worry about it it is that worrying about it is hard, and leads to problems like the one you've had here.
To use fgets strictly correctly, while worrying about the possibility that the user's input overflows the buffer, means detecting that it happened. If fgets didn't read all the input, that means it's still sitting there on the input stream, waiting to confuse the rest of your program. In that case, yes, you have to read or "flush" or discard it. That's what your line
while((ch = getchar()) != '\n' && ch != EOF);
tries to do — but the point is that you need to do that only if fgets had the not-big-enough problem. If fgets didn't have the problem — if the buffer was big enough — you don't want to do the flush-the-input thing, because it'll gobble up the user's next line of intended input instead, as you've discovered.
Now, with this said, I have to caution you. In general, a strategy of "make your arrays huge, so you don't have to worry about the possibility that they're not big enough" is not a good strategy. In the general case, that strategy leads to insecure programs and horrible security problems due to buffer overruns.
In this case, though, the problem isn't too bad. fgets is going to do its best not to write more into the destination array than the destination array can hold. (fgets will do a perfect job of this — a perfect job of avoiding buffer overflow — if you pass the size correctly, that is, if you fix problem one.) If the buffer isn't big enough, the worst problem that will happen is that the too-long part of the input line will stay on the input stream and get read buy a later input function, thus confusing things.
So you do always want to think about the exceptional cases, and think about what your program is going to do under all circumstances, not just the "good" ones. And for "real" programs, you do have to strive to make the behavior correct for all cases. For a beginning program like this one, though, I think most people would agree that it's fine to just use a huge buffer, and be done with it.
If you want to go for the extra credit, and perfectly handle the case where the user typed more than the fgets input buffer will hold, you're going to first have to detect that case. The code would look something like:
if(fgets(guess, guess_size, stdin) == NULL)
{
printf("error");
exit(EXIT_FAILURE);
}
if(guess[strlen(guess)-1] != '\n')
{
/* buffer wasn't big enough */
int ch = 0;
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
/* now print an error message or something, */
/* and ask the user to try again with shorter input */
}
But the point is that you do the while((ch = getchar()) != '\n' && ch != EOF) thing only in the case where fgets failed to read the whole line, not in the case where it succeeded.
If you're still with me, here are two somewhat-important footnotes.
I suggested changing your get_input function to take a second parameter int guess_size, but it turns out a better type to use for the sizes of things is size_t, so a better declaration would be size_t guess_size.
I suggested the test if(guess[strlen(guess)-1] != '\n') to detect that fgets wasn't able to read a full line, but that could fail (pretty badly) in the obscure case where fgets somehow returned an empty line. In that case strlen(guess) would be 0, and we'd end up accessing guess[-1] to see if it was the newline character, which is undefined and wrong. In practice it's probably impossible for fgets to return an empty string (at least, as long as you give it a buffer bigger than 1 to read into), but it's probably easier to write the code in a safer way than to convince yourself that it can't happen. There are a bunch of questions elsewhere on SO about practically and efficiently detecting the case that fgets didn't read a full line successfully, but just now I can't find any of them.

C. Using more memory than allocated in malloc - can I return sth, end program instead of letting it crash?

My program crashes when malloc(x*sizeof(char)), x < limit of fgets, despite buffer == NULL check.
In my example, when x is 1, and limit of what fgets can take is 100, and user types eg. 5 characters from keyboard (fgets() call), program crashes, returning some random like: 19284791298 value.
My problem: instead of crashing, I would prefer if it returned NULL.
Reason: I upload my code to my univ's linux platform that tests program's reaction to heap limit change to 0 and to 130, when my program is written to return NULL if user's input exceeds 100 characters. I don't quite understand how the environment changes memory limit to 0 and 130 and what exactly is changed, but even though, I noticed my program in CodeBlocks, windows 10, crashes in this situation described here (x < stdin input) despite checking buffer == NULL.
I wish buffer == NULL check could somehow work and prevent the crash.
If x was 100, and size was 1 (instead of 1 and 100), my program would return NULL and set err_code to 1.
I'm thinking: I can't do with x the same "if" statement I did for strlen(buffer), because... to check how long input written to buffer is, firstly I'd need to check length of what was written to this buffer?!.
printf("Insert data: ");
char *buffer = (char* )malloc(1*sizeof(char));
if (buffer == NULL)
return NULL;
int size=100;
if (fgets(buffer, size, stdin)!=NULL) {
if (strlen(buffer)>(unsigned)(size-2)) { //'\0' and enter are 2 chars
free(buffer);
*err_code=1;
return NULL;
}
//... here goes some sscanf to fill struct fields, etc.
}
In other words.
A bit condensed what I think may lead to understanding of my problem:
Is there a way to end program returning something, instead of letting it crash in such situation? A way to make if(buffer == NULL) work? Why doesn't this check work?
I'm unfamiliar with linux. When I see a comment in report I get, that linux sets (heap?) limit to 0 or 130 (when testing my program), does it mean I can replicate the problems it encounters by setting my x to 0, 130? (in the part malloc(x*sizeof(char)).
When you call fgets, you must tell it how big the destination buffer is. You are not just telling it the maximum number of characters you want it to read, so that it can automatically allocate that much space, or anything like that. You are telling it what the size of the buffer already is, and you are telling fgets that it absolutely must not read any more characters than that, otherwise the buffer will overflow. (fgets never does any allocating of its own.)
So when you say
char *buffer = (char* )malloc(1*sizeof(char));
followed by
int size=100;
fgets(buffer, size, stdin)
you have lied. You have allocated a buffer of size 1, and you have told fgets that the buffer is of size 100. So fgets will read up to 99 characters, and store them into buf, and in most cases this will badly overflow the buffer.
What you want to do is something more like this:
int size = 100;
char *buffer = (char* )malloc(size*sizeof(char));
if (buffer == NULL)
return NULL;
if (fgets(buffer, size, stdin)!=NULL) {
...
Also, although it doesn't have anything to do with your problem, there is no need to multiply by sizeof(char) when calling malloc, and in C, there is no need to cast the return from malloc into the destination pointer type, either. I would just call
char *buffer = malloc(size);
In your code, you have allocated buffer as a single byte array
char *buffer = (char* )malloc(1*sizeof(char));
int size=100;
if (fgets(buffer, size, stdin)!=NULL) {
In the fgets, you would want to read into buffer an input of 100 bytes. When the input is read into the buffer it goes beyond the allocated area and overwrites other data. Because of this, your program crashes,

Translation limit in C

I am attempting to capture input from the user via scanf:
char numStrings[5000];
printf("Enter string of numbers:\n\n");
scanf("%s", numStrings);
However, the length of the string that is inputted is 5000 characters. The translation limit in c99 is 4095 characters. Do I need to instruct the user to break their input in half or is there a better work around that I cannot think of?
You can input a string a lot larger than that, the stack is at least 1MB in common OS's, it's 8MB's on Linux, so that's the actual limit, 1M is 1024KB so you could for example try with 512KB which is 524288B
char string[524288];
scanf("%524287s", string);
will be most likely ok, if it's still too small, then use malloc().
No, you do not need to instruct the user to separate the input if it goes over a set length. The limit is on string literals, not strings. See the answer in this stackoverflow thread for more information. If you don't know what a reasonable max length is, then I would recommend using getline() or getdelim() if the delimiter that you want to use is not a line break.
Do I need to instruct the user to break their input in half or is there a better work around that I cannot think of?
As far as the code you've given goes, if the input word is longer than 4999 bytes then you can expect a buffer overflow. Yes, it would be wise to let someone (e.g. the user, or the guy who maintains this code next) know that's the maximum length. It's nice that you can truncate the input by using code like this: scanf("%4999s" "%*[^ \n]", numStrings);... The %*[^ \n] directive performs the truncation, in this case.
It'd be nicer yet if you can let the user know at the time that they overflow the buffer, but scanf doesn't make that an easy task. What would be even nicer (for the user, I mean) is if you could use dynamic allocation.
Ahh, the problem of dynamically sized input. If it can be avoided, then avoid it. One common method to avoid this problem is to require input in the form of argv, rather than stdin... but that's not always possible, useful or feasible.
scanf doesn't make this problem a particularly easy one to solve; in fact, it'd be much easier to solve if there were a similar functionality provided by %s in the form of an interface similar to fgets.
Without further adieu, here's an adaptation of the code I wrote in this answer, adapted for the purpose of reading (and simultaneously allocating) words in a similar procedure to that behind %s, rather than lines in a similar procedure to that behind fgets. Feel free to read that answer if you would like to know more about the inspiration behind it.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
char *get_dynamic_word(FILE *f) {
size_t bytes_read = 0;
char *bytes = NULL;
int c;
do {
c = fgetc(f);
} while (c >= 0 && isspace(c));
do {
if ((bytes_read & (bytes_read + 1)) == 0) {
void *temp = realloc(bytes, bytes_read * 2 + 1);
if (temp == NULL) {
free(bytes);
return NULL;
}
bytes = temp;
}
bytes[bytes_read] = c >= 0 && !isspace(c)
? c
: '\0';
c = fgetc(f);
} while (bytes[bytes_read++]);
if (c >= 0) {
ungetc(c, f);
}
return bytes;
}

Why is fgets() and strncmp() not working in this C code for string comparison?

This is a very fun problem I am running into. I did a lot of searching on stack overflow and found others had some similar problems. So I wrote my code accordingly. I originally had fscan() and strcmp(), but that completely bombed on me. So other posts suggested fgets() and strncmp() and using the length to compare them.
I tried to debug what I was doing by printing out the size of my two strings. I thought, maybe they have /n floating in there or something and messing it up (another post talked about that, but I don't think that is happening here). So if the size is the same, the limit for strncmp() should be the same. Right? Just to make sure they are supposedly being compared right. Now, I know that if the strings are the same, it returns 0 otherwise a negative with strncmp(). But it's not working.
Here is the output I am getting:
perk
repk
Enter your guess: perk
Word size: 8 and Guess size: 8
Your guess is wrong
Enter your guess:
Here is my code:
void guess(char *word, char *jumbleWord)
{
size_t wordLen = strlen(word);
size_t guessLen;
printf("word is: %s\n",word);
printf("jumble is: %s\n", jumbleWord);
char *guess = malloc(sizeof(char) * (MAX_WORD_LENGTH + 1));
do
{
printf("Enter your guess: ");
fgets(guess, MAX_WORD_LENGTH, stdin);
printf("\nword: -%s- and guess: -%s-", word, guess);
guessLen = strlen(guess);
//int size1 = strlen(word);
//int size2 = strlen(guess);
//printf("Word size: %d and Guess size: %d\n",size1,size2);
if(strncmp(guess,word,wordLen) == 0)
{
printf("Your guess is correct\n");
break;
}
}while(1);
}
I updated it from suggestions below. Especially after learning the difference between char * as a pointer and referring to something as a string. However, it's still giving me the same error.
Please note that MAX_WORD_LENGTH is a define statement used at the top of my program as
#define MAX_WORD_LENGTH 25
Use strlen, not sizeof. Also, you shouldn't use strncmp here, if your guess is a prefix of the word it will mistakenly report a match. Use strcmp.
sizeof(guess) is returning the size of a char * not the length of the string guess. Your problem is that you're using sizeof to manage string lengths. C has a function for string length: strlen.
sizeof is used to determine the size of data types and arrays. sizeof only works for strings in one very specific case - I won't go into that here - but even then, always use strlen to work with string lengths.
You'll want to decide how many characters you'll allow for your words. This is a property of your game, i.e. words in the game are never more that 11 characters long.
So:
// define this somewhere, a header, or near top of your file
#define MAX_WORD_LENGTH 11
// ...
size_t wordlen = strlen(word);
size_t guessLen;
// MAX_WORD_LENGTH + 1, 1 more for the null-terminator:
char *guess = malloc(sizeof(char) * (MAX_WORD_LENGTH + 1));
printf("Enter your guess: ");
fgets(guess, MAX_WORD_LENGTH, stdin);
guessLen = strlen(guess);
Also review the docs for fgets and note that the newline character is retained in the input, so you'll need to account for that if you want to compare the two words. One quick fix for this is to only compare up to the length of word, and not the length of guess, so: if( strncmp(guess, word, wordLen) == 0). The problem with this quick fix is that it will pass invalid inputs, i.e. if word is eject, and guess is ejection, the comparison will pass.
Finally, there's no reason to allocate memory for a new guess in each iteration of the loop, just use the string that you've already allocated. You could change your function setup to:
char guess(char *word, char *jumbledWord)
{
int exit;
size_t wordLen = strlen(word);
size_t guessLen;
char *guess = malloc(sizeof(char) * (MAX_WORD_LENGTH + 1));
do
{
printf("Enter your guess: ");
// ...
As everyone else has stated, use strlen not sizeof. The reason this is happening though, is a fundamental concept of C that is different from Java.
Java does not give you access to pointers. Not only does C have pointers, but they are fundamental to the design of the language. If you don't understand and use pointers properly in C then things won't make sense, and you will have quite a bit of trouble.
So, in this case, sizeof is returning the size of the char * pointer, which is (usually) 4 or 8 bytes. What you want is the length of the data structure "at the other end" of the pointer. This is what strlen encapsulates for you.
If you didn't have strlen, you would need to dereference the pointer, then walk the string until you find the null byte marking the end.
i = 1;
while(*guess++) { i++ }
Afterwards, i will hold the length of your string.
Update:
Your code is fine, except for one minor detail. The docs for fgets note that it will keep the trailing newline char.
To fix this, add the following code in between the fgets and strncmp sections:
if ( guess[guessLen-1] == '\n' ) {
guess[guessLen-1] = '\0';
}
That way the trailing newline, if any, gets removed and you are no longer off by one.
Some list of problems / advices for your code, much too long to fit in a comment:
your function returns a char which is strange. I don't see the
logic and what is more important, you actually never return a value. Don't do that, it will bring you trouble
look into other control structures in C, in particular don't do your exit thing. First, exit in C is a function, which does what it says, it exits the program. Then there is a break statement to leave a loop.
A common idiom is
do {
if (something) break;
} while(1)
you allocate a buffer in each iteration, but you never free it. this will give you big memory leaks, buffers that will be wasted and inaccessible to your code
your strncmp approach is only correct if the strings have the same length, so you'd have to test that first

Reading strings and integers from one binary text in C

I'm using C and I want to read from a binaryFile.
I know that it is contain strings in the following way: Length of a string, the string itself, the length of a string, string itself, and so on...
I want to count the number of times which the string Str appears in the binary file.
So I want to do something like this:
int N;
while (!feof(file)){
if (fread(&N, sizeof(int), 1, file)==1)
...
Now I need to get the string itself. I know it's length. Should I do a 'for'
loop and get with fgetc char by char? I know I'm not allowed to use fscanf since
it's not a text file, but can I use fgetc? And would I get what I'm expecting for
my string? (To use dynamic allocation for char* for it with the size of the length
and use strcpy to add it to the current string?)
You could allocate some memory with malloc then fread into that buffer:
char *str;
/* ... */
if (fread(&N, sizeof(int), 1, file)==1)
{
/* check that N > 0 */
str = malloc(N+1);
if (fread(str, sizeof(char), N, file) == N)
{
str[N] = '\0'; /* terminate str */
printf("Read %d chars: %s\n", N, str);
}
free(str);
}
You should probably loop on:
while (fread(&N, sizeof(int), 1, file) == 1)
{
// Check N for sanity
char *buffer = malloc(N+1);
// Check malloc succeeded
if (fread(buffer, N, 1, file) != 1)
...process error...
buffer[N] = '\0'; // Null terminate for sanity's sake
...store buffer (the pointer) for later processing so you aren't leaking...
...or free it if you won't need it later...
}
You could use getc() or fgetc() in a loop; that would work. However, the direct fread() is much simpler (and is coded as if it uses getc() in a loop).
You might want to do some sanity checking on N before blindly using it with malloc(). In particular, negative values are likely to lead to much unhappiness.
The file format as written is tied to one class of machine — either big-endian or little-endian, and with the fixed size of int (probably 32-bits). Writing more portable data is slightly fiddlier, but eminently doable — but probably not relevant to you just yet.
Using feof() is seldom the correct way to test for whether to continue with a loop. Indeed, there is not often a need to use feof() in code. When it is used, it is because an I/O operation 'failed' and you need to disambiguate between 'it was not an error — just EOF' and 'there was some sort of error on the device'.

Resources