I wonder why the two values of int don't validate the if condition even if it is true. printf shows both of them are equal.
Is buffer overflow able to affect the behavior of if conditions,corrupting other code sections behavior.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
srand(time(NULL));
char instring[2]; // when this increases somehow I get the right behavior
int inint;
int guess;
guess = rand() % 127;
inint = ~guess;
printf("%i\n", guess); //testing with printf()
while (guess != inint) {
printf("Guess Number\r\n");
gets(instring);
inint = atoi(instring);
printf("%i\n", inint);
if (inint > guess) {
printf("%i\n", inint);
puts("too high");
} else if (guess > inint) {
puts("too low");
} else {
puts("right");
}
}
return 0;
}
The problem is indeed here.
char instring[2];
Now let's think about this line.
gets(instring);
Let's say you type 10 and hit enter. What will go into instring is three bytes.
1
0
A terminating null.
instring can only hold two bytes, but gets will shove (at least) three in anyway. That extra byte will overflow into adjacent memory corrupting some other variable's memory causing some bizarre bug.
And that's why making instring large enough to hold the result from gets fixes the program.
To avoid this when working with strings, use functions which limit themselves to the memory available. In this case fgets.
fgets(instring, sizeof(instring), stdin);
That will limit itself to only reading as much as it can fit into instring.
In general, don't get stingy with memory to read input. A common practice is to allocate one large buffer for reading input, 1024 is good, and reuse that buffer just for reading input. The data is copied out of it to more appropriately sized memory, which atoi effectively does for you.
Related
I have a simple code that suppose to read length sized and fetch data from character device in Linux C.
This is my code and errno is set to 9. I made sure the file exists and it does. And able to read it with cat /dev/mychardev-0 but why bad file descriptor error at time of read. I am getting this line passed int fd=open("/dev/mychardev-0",O_RDONLY); if(fd<0)
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
int fd=open("/dev/mychardev-0",O_RDONLY);
if(fd<0)
{
printf("fd %d\n",fd);
exit(0);
}
int length=1024000;
int x=0;
char buffer[length-1];
while(x<length)
{
int valread=read(fd,&buffer[x],length);
if(valread==0)
{
printf("zero bytes read\n");
break;
}
if(valread<0)
{
printf("read return negative %d %d\n",valread,errno);
break;
}
x=x+valread;
}
if(x>0)
{
printf("%x",buffer);
}
else
{
printf("ops no read\n");
}
return 0;
}
char buffer[length-1];
int valread=read(fd,&buffer[x],length);
That is a very bad idea. You allocate enough space for length - 1 bytes then attempt to read length bytes into that space.
If the read gets the largest possible size, you will have a buffer overflow, well into undefined behaviour territory(1).
And, on top of that, you attempt to read length bytes even though you may have already read some in earlier iterations of the loop. You should be:
Using the correct length for the buffer; and
Adjusting the length down based on what you've already read.
And, though this may not be a problem, one meg is quite a lot of data to put on the stack (which is often limited in size by default). If that is the case, you may be better of using malloc to get a dynamic buffer, such as:
char *buffer = malloc(length);
// make sure buffer != NULL, then use it.
free(buffer);
So, something like (untested but you should hopefully get the idea):
int x = 0, length = 1024000; // with malloc if needed.
char buffer[length];
while (x < length) {
int valread = read(fd, &buffer[x], length - x);
if (valread == 0) {
printf("zero bytes read\n");
break;
}
else if (valread < 0) {
printf("read return negative %d %d\n",valread,errno);
break;
}
x += valread;
}
(1) An example of what may happen is that overflowing the buffer will affect other variables on the stack in certain ways.
For example, it may corrupt x which would mean your next read could go to some arbitrary place in memory possibly corrupting other things as a result.
Or it could corrupt fd which would make the next read likely to fail with an invalid file descriptor.You can check the actual behaviour by simply printing out those two values before any use. Given the fact you mention "bad file descriptor error", that's possibly the most likely scenario here.
But, to be honest, the best solution is probably just to avoid undefined behaviour (though it may still be educational for you to find out the effects).
I know that there is a question with the same name, but it didn't work for me.
I'm making a home-compiler, returns the words that belongs to a language.
The words to analyze are in this vector:
char *cadenas[]= {"123", "4567L", "5a23", '\0'};
Now I want to enter the words by console, but strings can't be used in C, how can I do it? (Without making a matrix possibly)
void getCadenas(char *cadenas[]){
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
char cadena[15];
gets(cadena);
int x=0;
while(cadena[0]!='z'){
strcpy(cadenas[x],cadena);
x++;
gets(cadena);
}
}
If I understand your problem correctly, you would like the user to be able to enter multiple strings, until he/she types z
See if this piece of code helps you out. The strings will be stored in the cadenas array, as requested.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define MAX_CADENAS 100
#define MAX_CADENA_LEN 255
int getCadenas(char **cadenas){
int x=0;
char cad[MAX_CADENA_LEN+1];
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
while(x<MAX_CADENAS) {
scanf("%s", cad);
if (strcmp(cad,"z")==0)
break;
cadenas[x] = malloc(strlen(cad)+1);
strcpy(cadenas[x], cad);
x++;
}
return x;
}
char *cadenas[MAX_CADENAS];
int main() {
int num, i;
num = getCadenas(cadenas);
for (i=0;i<num; i++) {
printf("%s\n", cadenas[i]);
}
}
Note0: the code assumes you know in advance what the maximum number of input strings can be (100). It also assumes a maximum size for each input string (255 characters)
Note1: gets is deprecated. Also, instead of scanf, you might want to use fgets.
Note2: the present code is for illustrative purpose only. It allocates memory for each input string, but it assumes no error occurs in doing so (i.e. it does not check what malloc returns).
Note3: the allocated memory blocks must be freed when not used anymore (hint: cycle through the cadenas array and use free)
Assuming you don't mind carrying on with fixed-size strings and arrays, here is your original program modified:
#include <stdio.h>
#include <string.h>
#define MAX_CADENAS 100
#define CADENA_LIMIT 1000
// ...
void getCadenas(char cadenas[MAX_CADENAS][CADENA_LIMIT]){
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
int x;
for(x=0; x<MAX_CADENAS-1; x++){
char cadena[CADENA_LIMIT];
fgets(cadena, CADENA_LIMIT, stdin);
// fgets will copy the newline character, we don't want that
int cadenaLength=strlen(cadena);
if(cadena[cadenaLength-1]=='\n')
cadena[cadenaLength-1]='\0';
if(strcmp(cadena, "z")==0) break;
strcpy(cadenas[x], cadena);
}
cadenas[x][0]='\0';
}
// ...
Prefer fgets as you can prevent overflow of the fixed-size strings. Unfortunately it copies the newline as well, so I have code to handle that. The result is an array in the form you originally specified (except it ends with "" which we decided was what you were after in the comments).
You can read arbitrary sized strings in C like in other languages, but you would need to implement it with malloc() and co. Allocating dynamically sized memory is primarily controlled with the functions malloc, calloc, realloc and free. This would make the program unavoidably more complicated. Here is one way of doing this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ...
char *getCadena(){
int length=0, capacity=1, character;
char *cadena=malloc(1); // sizeof(char) is always 1
while((character=getchar())!=EOF){
if(character=='\n') break;
// Add character to string
length++;
if(capacity<length){
capacity*=2;
cadena=realloc(cadena,capacity);
}
cadena[length-1]=character;
}
// Add terminator to cadena
length++;
if(capacity<length){
capacity*=2;
cadena=realloc(cadena,capacity);
}
cadena[length-1]='\0';
return cadena;
}
char **getCadenas(){
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
int length=0, capacity=1;
char **cadenas=malloc(sizeof(char *));
for(;;){
char *cadena=getCadena();
if(strcmp(cadena,"z")==0){
free(cadena);
break;
}
// Add pointer to cadenas array
length++;
if(capacity<length){
capacity*=2;
cadenas=realloc(cadenas,capacity*sizeof(char *));
}
cadenas[length-1]=cadena;
}
// Add NULL to end of cadenas
length++;
if(capacity<length){
capacity*=2;
cadenas=realloc(cadenas,capacity*sizeof(char *));
}
cadenas[length-1]=NULL;
return cadenas;
}
void freeCadenas(char **cadenas){
int i=0;
while(cadenas[i]!=NULL){
free(cadenas[i]);
i++;
}
free(cadenas);
}
// ...
This works mostly the same as the previous function, except you should use freeCadenas eventually, and I end the array with NULL instead of "" which is customary.
The code is a lot longer, but it's pretty typical of more sophisticated C code with less arbitrary limits. In fact real C code usually has more robust handling of errors and more generic functions for managing dynamic arrays. If you actually manage to make this "home-compiler", however, you will figure all this out for yourself.
What follows are abbreviated just to keep this question short (no check for null, etc.).
program1.c
main()
{
char *aString = calloc(10, sizeof(char));
printf("Enter string: ");
scanf("%s", aString);
printf("You typed in %s\n", aString);
}
program2.c
main()
{
char aString[10];
printf("Enter string: ");
scanf("%s", aString);
printf("You typed in %s\n", aString);
}
program1.c will let me enter characters seemingly forever. I've entered 2000+ characters and the program will execute without error, despite the fact that this is "undefined behavior".
program2.c will let me enter more than 10 characters, but if get close to like 30 or 40 characters, it will give me a segmentation fault.
Now my limited understanding from class and other tutorials tells me that both of these programs are doing the same thing under the hood --- setting aside a piece of memory intended to be an array of chars of length 10. But it seems that program2.c's implementation provides some degree of safety. Or is the segmentation fault error completely random when you exceed the granted memory space, and I just happen to be getting it with program2.c just because that's the mood my computer is in right now?
What is the difference between program1.c and program2.c, and which is the "safer" method of entering a string? I realize there are other methods which may be even better, but I'm curious about the comparison between just these two.
Although neither program is safe, the likely reason you are seeing the behavior is that program B allocates the array on the stack, and as soon as you get out of bounds you are overwriting other useful things like the stack frame of the scanf call.
Whereas program A allocates heap memory, and since you are not doing anything else in this toy program, the memory you are writing into is unused.
In any real program, both are equally unsafe.
Note: This out-of-bounds behavior is undefined by the C standard, and the compiler could theoretically be doing anything. But in most common real-world compilers, the above is most likely what actually happens.
The two are not the same under the hood.
program1 is calling calloc to allocate memory from the heap.
program2 has been compiled to reserve additional space on the stack when the function is called.
Both programs are exploitable because you are not checking any bounds when you call scanf(). He is free to write as many bytes as he wishes to either buffer. The solution here is scanf("%9s", aString), which tells scanf to only write up to 9+1 bytes.
What and where are the stack and heap?
Assuming a typical modern operating system, your program 1 does not crash because calloc had to request an entire page (4096 bytes of RAM, usually) from the OS to satisfy the request for 10 bytes. If you feed that program sufficiently many characters, it will crash. However, writing even one byte more than the overtly requested size (10 bytes) is forbidden, and has an excellent chance of corrupting the internal data structure used to keep track of "heap" allocations. It is probable that if you added another malloc or free call to this program, after the scanf, it would crash inside that malloc or free. By way of illustration, consider this program:
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *p = malloc(23);
memcpy(p, "abcdefghijklmnopqrstuvwx", 25);
char *q = malloc(1);
return 0;
}
➽
$ MALLOC_CHECK_=1 ./a.out
*** Error in `./a.out': malloc: top chunk is corrupt: 0x0000000001bc4020 ***
(On this system, copying only 24 bytes does not crash. Do not rely on this information.)
Program 2, meanwhile, is probably crashing not because the scanf call wrote all the way to unmapped memory (which, for similar reasons, would require far more bytes of input) but because data on the stack is very densely packed and it clobbered something critical, e.g. the address to which main should return.
In a program that does anything even a little more complicated than your examples, both "techniques" are equally dangerous -- both heap and stack overflows can and have lead to catastrophic security holes.
You explicitly asked for a comparison between your two unsafe techniques, but for the benefit of future readers I am going to describe two much better techniques for reading strings from standard input. If your C library includes it, the best option is getline, which (in a simple program like this) would be used like so:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *line = 0;
size_t n = 0;
ssize_t r;
fputs("Enter a string: ", stdout);
fflush(stdout);
r = getline(&line, &n, stdin);
if (r == -1) {
perror("getline");
return 1;
}
if (r > 0 && line[r-1] == '\n')
line[r-1] = '\0';
printf("You entered %s\n", line);
free(line);
return 0;
}
If you don't have getline, and you need to read an arbitrarily long string from the user, your best option is to implement getline yourself (gnulib has an implementation you can borrow, if your code can be released under the GPL). But an acceptable alternative in many cases is to place an upper limit on input length, at which point you can use fgets:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LEN 81
int main(void)
{
char *line = malloc(MAX_LINE_LEN);
size_t n;
fputs("Enter a string: ", stdout);
fflush(stdout);
if (!fgets(line, MAX_LINE_LEN, stdin)) {
perror("fgets");
return 1;
}
n = strlen(line);
if (line[n] != '\n') {
fprintf(stderr, "string too long - %u characters max\n", MAX_LINE_LEN);
return 1;
}
line[n] = '\0';
printf("You entered %s\n", line);
free(line);
return 0;
}
Notes:
sizeof(char) == 1 by definition; therefore, sizeof(char) should never appear in well-written code. If you want to use calloc to allocate a prezeroed array of characters, write calloc(1, nchars).
Never use scanf, fscanf, or sscanf.
Do not confuse fgets with gets. fgets is safe if used correctly; it is impossible to use gets safely.
I'm a novice programmer, but usually I can unravel my own issues. This time I solved the issue, but it still stumps me. A friend suggested I ask this community for input.
I'm trying to print numbers in C. I have a function to do this using sprintf. The numbers should never be more than 2 digits so I use a 2-character buffer. Somehow this is where my logic fails, because this causes an infinite loop by modifying one of the variables passed to sprintf, but increasing the buffer size solves the issue.
Here's the failing code:
#include <stdio.h>
void printarray(int array[][4]) {
int y;
int z;
char buf[2];
for (y=0; y<4; y++) {
for (z=0; z<4; z++) {
sprintf(buf, "%d", array[y][z]);
printf("buf is %s, y is %d and z is %d\n",buf,y,z);
}
}
}
int main() {
int arr[4][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0} };
printarray(arr);
return 0;
}
as soon as y gets to 2, it gets reset back to 0, thus infinite loop. changing buf[2] to buf[8] solves the issue.
You're forgetting the NUL terminator. In C, strings require an extra character for the terminator, so char buf[2] ought to be char buf[3] to accommodate numbers between 10 and 99.
Incidentally, your code demonstrates why sprintf is dangerous as it can write past the output buffer and enable stack smashing attacks. A better options is to use snprintf.
C strings are null terminated. If you have 2 characters ("10" for example) you need a buffer sized 2 + 1 for the null terminator.
sprintf() adds this to the end of your buffer; in your current case you actually have a buffer overflow because you're not providing enough space.
The modern, safer approach is to use snprintf() to which you supply the length of the buffer.
I assume that sprintf adds a \0 at the end of the generated string. So for instance if you print the number 99, you'd get "99\0" in your buffer, so for a buffer with length 2, that causes problems.
I've been doing a fairly easy program of converting a string of Characters (assuming numbers are entered) to an Integer.
After I was done, I noticed some very peculiar "bugs" that I can't answer, mostly because of my limited knowledge of how the scanf(), gets() and fgets() functions work. (I did read a lot of literature though.)
So without writing too much text, here's the code of the program:
#include <stdio.h>
#define MAX 100
int CharToInt(const char *);
int main()
{
char str[MAX];
printf(" Enter some numbers (no spaces): ");
gets(str);
// fgets(str, sizeof(str), stdin);
// scanf("%s", str);
printf(" Entered number is: %d\n", CharToInt(str));
return 0;
}
int CharToInt(const char *s)
{
int i, result, temp;
result = 0;
i = 0;
while(*(s+i) != '\0')
{
temp = *(s+i) & 15;
result = (temp + result) * 10;
i++;
}
return result / 10;
}
So here's the problem I've been having. First, when using gets() function, the program works perfectly.
Second, when using fgets(), the result is slightly wrong because apparently fgets() function reads newline (ASCII value 10) character last which screws up the result.
Third, when using scanf() function, the result is completely wrong because first character apparently has a -52 ASCII value. For this, I have no explanation.
Now I know that gets() is discouraged to use, so I would like to know if I can use fgets() here so it doesn't read (or ignores) newline character.
Also, what's the deal with the scanf() function in this program?
Never use gets. It offers no protections against a buffer overflow vulnerability (that is, you cannot tell it how big the buffer you pass to it is, so it cannot prevent a user from entering a line larger than the buffer and clobbering memory).
Avoid using scanf. If not used carefully, it can have the same buffer overflow problems as gets. Even ignoring that, it has other problems that make it hard to use correctly.
Generally you should use fgets instead, although it's sometimes inconvenient (you have to strip the newline, you must determine a buffer size ahead of time, and then you must figure out what to do with lines that are too long–do you keep the part you read and discard the excess, discard the whole thing, dynamically grow the buffer and try again, etc.). There are some non-standard functions available that do this dynamic allocation for you (e.g. getline on POSIX systems, Chuck Falconer's public domain ggets function). Note that ggets has gets-like semantics in that it strips a trailing newline for you.
Yes, you want to avoid gets. fgets will always read the new-line if the buffer was big enough to hold it (which lets you know when the buffer was too small and there's more of the line waiting to be read). If you want something like fgets that won't read the new-line (losing that indication of a too-small buffer) you can use fscanf with a scan-set conversion like: "%N[^\n]", where the 'N' is replaced by the buffer size - 1.
One easy (if strange) way to remove the trailing new-line from a buffer after reading with fgets is: strtok(buffer, "\n"); This isn't how strtok is intended to be used, but I've used it this way more often than in the intended fashion (which I generally avoid).
There are numerous problems with this code. We'll fix the badly named variables and functions and investigate the problems:
First, CharToInt() should be renamed to the proper StringToInt() since it operates on an string not a single character.
The function CharToInt() [sic.] is unsafe. It doesn't check if the user accidentally passes in a NULL pointer.
It doesn't validate input, or more correctly, skip invalid input. If the user enters in a non-digit the result will contain a bogus value. i.e. If you enter in N the code *(s+i) & 15 will produce 14 !?
Next, the nondescript temp in CharToInt() [sic.] should be called digit since that is what it really is.
Also, the kludge return result / 10; is just that -- a bad hack to work around a buggy implementation.
Likewise MAX is badly named since it may appear to conflict with the standard usage. i.e. #define MAX(X,y) ((x)>(y))?(x):(y)
The verbose *(s+i) is not as readable as simply *s. There is no need to use and clutter up the code with yet another temporary index i.
gets()
This is bad because it can overflow the input string buffer. For example, if the buffer size is 2, and you enter in 16 characters, you will overflow str.
scanf()
This is equally bad because it can overflow the input string buffer.
You mention "when using scanf() function, the result is completely wrong because first character apparently has a -52 ASCII value."
That is due to an incorrect usage of scanf(). I was not able to duplicate this bug.
fgets()
This is safe because you can guarantee you never overflow the input string buffer by passing in the buffer size (which includes room for the NULL.)
getline()
A few people have suggested the C POSIX standard getline() as a replacement. Unfortunately this is not a practical portable solution as Microsoft does not implement a C version; only the standard C++ string template function as this SO #27755191 question answers. Microsoft's C++ getline() was available at least far back as Visual Studio 6 but since the OP is strictly asking about C and not C++ this isn't an option.
Misc.
Lastly, this implementation is buggy in that it doesn't detect integer overflow. If the user enters too large a number the number may become negative! i.e. 9876543210 will become -18815698?! Let's fix that too.
This is trivial to fix for an unsigned int. If the previous partial number is less then the current partial number then we have overflowed and we return the previous partial number.
For a signed int this is a little more work. In assembly we could inspect the carry-flag, but in C there is no standard built-in way to detect overflow with signed int math. Fortunately, since we are multiplying by a constant, * 10, we can easily detect this if we use an equivalent equation:
n = x*10 = x*8 + x*2
If x*8 overflows then logically x*10 will as well. For a 32-bit int overflow will happen when x*8 = 0x100000000 thus all we need to do is detect when x >= 0x20000000. Since we don't want to assume how many bits an int has we only need to test if the top 3 msb's (Most Significant Bits) are set.
Additionally, a second overflow test is needed. If the msb is set (sign bit) after the digit concatenation then we also know the number overflowed.
Code
Here is a fixed safe version along with code that you can play with to detect overflow in the unsafe versions. I've also included both a signed and unsigned versions via #define SIGNED 1
#include <stdio.h>
#include <ctype.h> // isdigit()
// 1 fgets
// 2 gets
// 3 scanf
#define INPUT 1
#define SIGNED 1
// re-implementation of atoi()
// Test Case: 2147483647 -- valid 32-bit
// Test Case: 2147483648 -- overflow 32-bit
int StringToInt( const char * s )
{
int result = 0, prev, msb = (sizeof(int)*8)-1, overflow;
if( !s )
return result;
while( *s )
{
if( isdigit( *s ) ) // Alt.: if ((*s >= '0') && (*s <= '9'))
{
prev = result;
overflow = result >> (msb-2); // test if top 3 MSBs will overflow on x*8
result *= 10;
result += *s++ & 0xF;// OPTIMIZATION: *s - '0'
if( (result < prev) || overflow ) // check if would overflow
return prev;
}
else
break; // you decide SKIP or BREAK on invalid digits
}
return result;
}
// Test case: 4294967295 -- valid 32-bit
// Test case: 4294967296 -- overflow 32-bit
unsigned int StringToUnsignedInt( const char * s )
{
unsigned int result = 0, prev;
if( !s )
return result;
while( *s )
{
if( isdigit( *s ) ) // Alt.: if (*s >= '0' && *s <= '9')
{
prev = result;
result *= 10;
result += *s++ & 0xF; // OPTIMIZATION: += (*s - '0')
if( result < prev ) // check if would overflow
return prev;
}
else
break; // you decide SKIP or BREAK on invalid digits
}
return result;
}
int main()
{
int detect_buffer_overrun = 0;
#define BUFFER_SIZE 2 // set to small size to easily test overflow
char str[ BUFFER_SIZE+1 ]; // C idiom is to reserve space for the NULL terminator
printf(" Enter some numbers (no spaces): ");
#if INPUT == 1
fgets(str, sizeof(str), stdin);
#elif INPUT == 2
gets(str); // can overflows
#elif INPUT == 3
scanf("%s", str); // can also overflow
#endif
#if SIGNED
printf(" Entered number is: %d\n", StringToInt(str));
#else
printf(" Entered number is: %u\n", StringToUnsignedInt(str) );
#endif
if( detect_buffer_overrun )
printf( "Input buffer overflow!\n" );
return 0;
}
You're correct that you should never use gets. If you want to use fgets, you can simply overwrite the newline.
char *result = fgets(str, sizeof(str), stdin);
char len = strlen(str);
if(result != NULL && str[len - 1] == '\n')
{
str[len - 1] = '\0';
}
else
{
// handle error
}
This does assume there are no embedded NULLs. Another option is POSIX getline:
char *line = NULL;
size_t len = 0;
ssize_t count = getline(&line, &len, stdin);
if(count >= 1 && line[count - 1] == '\n')
{
line[count - 1] = '\0';
}
else
{
// Handle error
}
The advantage to getline is it does allocation and reallocation for you, it handles possible embedded NULLs, and it returns the count so you don't have to waste time with strlen. Note that you can't use an array with getline. The pointer must be NULL or free-able.
I'm not sure what issue you're having with scanf.
never use gets(), it can lead to unprdictable overflows. If your string array is of size 1000 and i enter 1001 characters, i can buffer overflow your program.
Try using fgets() with this modified version of your CharToInt():
int CharToInt(const char *s)
{
int i, result, temp;
result = 0;
i = 0;
while(*(s+i) != '\0')
{
if (isdigit(*(s+i)))
{
temp = *(s+i) & 15;
result = (temp + result) * 10;
}
i++;
}
return result / 10;
}
It essentially validates the input digits and ignores anything else. This is very crude so modify it and salt to taste.
So I am not much of a programmer but let me try to answer your question about the scanf();. I think the scanf is pretty fine and use it for mostly everything without having any issues. But you have taken a not completely correct structure. It should be:
char str[MAX];
printf("Enter some text: ");
scanf("%s", &str);
fflush(stdin);
The "&" in front of the variable is important. It tells the program where (in which variable) to save the scanned value.
the fflush(stdin); clears the buffer from the standard input (keyboard) so you're less likely to get a buffer overflow.
And the difference between gets/scanf and fgets is that gets(); and scanf(); only scan until the first space ' ' while fgets(); scans the whole input. (but be sure to clean the buffer afterwards so you wont get an overflow later on)