Best way to do binary arithmetic in C? - c

I am learning C and writing a simple program that will take 2 string values assumed to each be binary numbers and perform an arithmetic operation according to user selection:
Add the two values,
Subtract input 2 from input 1, or
Multiply the two values.
My implementation assumes each character in the string is a binary bit, e.g. char bin5 = "0101";, but it seems too naive an approach to parse through the string a character at a time. Ideally, I would want to work with the binary values directly.
What is the most efficient way to do this in C? Is there a better way to treat the input as binary values rather than scanf() and get each bit from the string?
I did some research but I didn't find any approach that was obviously better from the perspective of a beginner. Any suggestions would be appreciated!

Advice:
There's not much that's obviously better than marching through the string a character at a time and making sure the user entered only ones and zeros. Keep in mind that even though you could write a really fast assembly routine if you assume everything is 1 or 0, you don't really want to do that. The user could enter anything, and you'd like to be able to tell them if they screwed up or not.
It's true that this seems mind-bogglingly slow compared to the couple cycles it probably takes to add the actual numbers, but does it really matter if you get your answer in a nanosecond or a millisecond? Humans can only detect 30 milliseconds of latency anyway.
Finally, it already takes far longer to get input from the user and write output to the screen than it does to parse the string or add the numbers, so your algorithm is hardly the bottleneck here. Save your fancy optimizations for things that are actually computationally intensive :-).
What you should focus on here is making the task less manpower-intensive. And, it turns out someone already did that for you.
Solution:
Take a look at the strtol() manpage:
long strtol(const char *nptr, char **endptr, int base);
This will let you convert a string (nptr) in any base to a long. It checks errors, too. Sample usage for converting a binary string:
#include <stdlib.h>
char buf[MAX_BUF];
get_some_input(buf);
char *err;
long number = strtol(buf, &err, 2);
if (*err) {
// bad input: try again?
} else {
// number is now a long converted from a valid binary string.
}
Supplying base 2 tells strtol to convert binary literals.

First out I do recommend that you use stuff like strtol as recommended by tgamblin,
it's better to use things that the lib gives to you instead of creating the wheel over and over again.
But since you are learning C I did a little version without strtol,
it's neither fast or safe but I did play a little with the bit manipulation as a example.
int main()
{
unsigned int data = 0;
int i = 0;
char str[] = "1001";
char* pos;
pos = &str[strlen(str)-1];
while(*pos == '0' || *pos == '1')
{
(*pos) -= '0';
data += (*pos) << i;
i++;
pos--;
}
printf("data %d\n", data);
return 0;
}

In order to get the best performance, you need to distinguish between trusted and untrusted input to your functions.
For example, a function like getBinNum() which accepts input from the user should be checked for valid characters and compressed to remove leading zeroes. First, we'll show a general purpose in-place compression function:
// General purpose compression removes leading zeroes.
void compBinNum (char *num) {
char *src, *dst;
// Find first non-'0' and move chars if there are leading '0' chars.
for (src = dst = num; *src == '0'; src++);
if (src != dst) {
while (*src != '\0')
*dst++ = *src++;
*dst = '\0';
}
// Make zero if we removed the last zero.
if (*num == '\0')
strcpy (num, "0");
}
Then provide a checker function that returns either the passed in value, or NULL if it was invalid:
// Check untested number, return NULL if bad.
char *checkBinNum (char *num) {
char *ptr;
// Check for valid number.
for (ptr = num; *ptr == '0'; ptr++)
if ((*ptr != '1') && (*ptr != '0'))
return NULL;
return num;
}
Then the input function itself:
#define MAXBIN 256
// Get number from (untrusted) user, return NULL if bad.
char *getBinNum (char *prompt) {
char *num, *ptr;
// Allocate space for the number.
if ((num = malloc (MAXBIN)) == NULL)
return NULL;
// Get the number from the user.
printf ("%s: ", prompt);
if (fgets (num, MAXBIN, stdin) == NULL) {
free (num);
return NULL;
}
// Remove newline if there.
if (num[strlen (num) - 1] == '\n')
num[strlen (num) - 1] = '\0';
// Check for valid number then compress.
if (checkBinNum (num) == NULL) {
free (num);
return NULL;
}
compBinNum (num);
return num;
}
Other functions to add or multiply should be written to assume the input is already valid since it will have been created by one of the functions in this library. I won't provide the code for them since it's not relevant to the question:
char *addBinNum (char *num1, char *num2) {...}
char *mulBinNum (char *num1, char *num2) {...}
If the user chooses to source their data from somewhere other than getBinNum(), you could allow them to call checkBinNum() to validate it.
If you were really paranoid, you could check every number passed in to your routines and act accordingly (return NULL), but that would require relatively expensive checks that aren't necessary.

Wouldn't it be easier to parse the strings into integers, and then perform your maths on the integers?
I'm assuming this is a school assignment, but i'm upvoting you because you appear to be giving it a good effort.

Assuming that a string is a binary number simply because it consists only of digits from the set {0,1} is dangerous. For example, when your input is "11", the user may have meant eleven in decimal, not three in binary. It is this kind of carelessness that gives rise to horrible bugs. Your input is ambiguously incomplete and you should really request that the user specifies the base too.

Related

Is using input parameters instead of local variables more efficient in C?

Consider the two functions below. Both functions compute the number of times a character appears in a string with a specified length.
int str_get_num_occurrences1(char * str, char c, unsigned int len){
if (!len)
len = strlen(str);
int res = 0;
int n = len;
for ( ; n--; )
if (str[n] == c)
res++;
return res;
}
int str_get_num_occurrences2(char * str, char c, unsigned int len){
int res = 0;
if (!len)
len = strlen(str);
for ( ; len--; )
if (str[len] == c)
res++;
return res;
}
Obviously, the two functions do the same thing. Besides the fact that the first function is a little bit more readable than the second, is the second function more efficient since it avoids a local variable? I'm sure that these particular functions are really too simple to measure a true difference. I'm asking in more of a general or theoretical way.
Are there reasons why a user should avoid using input parameters as temporary storage (besides readability)? I'm not asking about pointers, where the input could be changed by the function. Does the compiler interpret the two functions differently which could cause function one to be preferred?
I searched through the questions, and I did find some related questions but none that I could find discussed the efficiency.
TL;DR
Write the code you find easiest to read/write/maintain. The difference between your functions will probably disappear when you compile with optimizations.
You might want to think about a couple of things that you can do to write a more flexible function, or at least: code that is easier to read. This answer will focus more on coding style, than the question Which is best, X or Y, because the answer will almost always be That depends on Z
Given that you're allowing the call to pass a 0 value for the string length, you could just write something like this:
int get_char_count(const char *str, char c)
{
int count = 0;
while(*str++) {
if (*str == c) {
++count;
}
}
return count;
}
That, to me, looks like the least amount of code, it's easy to read, and easy to maintain.
The drawbacks are:
Strings with '\0' characters in the middle (ie char[][]) can't be processed in full in a single call using this approach
Not possible to get the char count in a part of the string.
Strings containing '\0' chars can't be processed in full
If you want to support those use cases, you'll have to add a length argument. But even then, I'd just add it to the function, and not call strlen:
int get_char_count(const char *str, char c, unsigned int len)
{
int count = 0;
if (!len) {
while(*str++) {
if (*str == c) {
++count;
}
}
return count; // return early
}
//len is given
while (len--) {
if (str[len] == c) {
++count;
}
}
return count;
}
Now that I'm able to specify how many characters to iterate over, rather than to return on '\0', I can use this function, for example, to count how many occurrences of a given character are in an array of strings:
Example: count in char[][]
Example: cont in part of a string
Example: string with nul-chars
The first case (char [][]) works because of how the arrays are stored in memory: An array is a contiguous block of memory, and all values are stored in succession. If you know the total size of said block, you can use a char[][] as though it is one big string. The result being: only 1 function call is needed to count a character in all elements of the array.
The last case is pretty much the same thing, because the string in the example is actually how an array of strings is stored.
The second example (counting in partial string) is self-evident: rather than specifying the length of the full string, you can specify the number of characters you want to check...
The same approach can be used for strings lacking a terminating nul character
Because this is a fairly trivial function to implement, it's common to see most of the brackets being omitted:
while (*str++)
if (*str == c)
++count;
//or even
while(len--) count += str[len] == c;
The last version is technically valid, but it's not as easy to read. Omitting brackets for one-line if's and simple loops is fairly common, but has been the cause of bugs, like the goto fail bug from a few years back.
One last style-related thing:
When using the pointer to iterate over the string like I did in the first snippet, some will tell you that the best thing to do is to create a local pointer to increment:
int get_char_count(const char *str, char c)
{
int count = 0;
const char *local = str;
while(*local++) {
if (*local == c) {
++count;
}
}
return count;
}
The obvious advantage here being that you're not losing the original position/pointer that was passed in. If you later add something to the function, you can always reassign, or assign a new pointer based off str.

Write a recursive function in C that converts a number into a string

I'm studying software engineering, and came across this exercise: it asks to write a recursive function in C language that receives a positive integer and an empty string, and "translates" the number into a string. Meaning that after calling the function, the string we sent would contain the number but as a string of its digits.
I wrote this function, but when I tried printing the string, it did print the number I sent, but in reverse.
This is the function:
void strnum(int n, char *str)
{
if(n)
{
strnum(n/10, str+1);
*str = n%10 + '0';
}
}
For example, I sent the number 123 on function call, and the output was 321 instead of 123.
I also tried exchanging the two lines within the if statement, and it still does the same. I can't figure out what I did wrong. Can someone help please?
NOTE: Use of while and for loop statements is not allowed for the exercise.
Note: your current implementation design is somewhat dangerous since you have no way of knowing if you are really writing in valid memory; consider implementing the function with a passed in len to know when you shouldn't try to write anymore; ie. to prevent buffer overruns.
Introduction
The problem is that you are shaving off the least significant digit, but assigning it to the most significant position in the buffer pointed to by str.
You will need to have the "off shaving" and the "assigning" synchronized, so that the least significant digit is stored at the end - and not the beginning.
Hints
Easiest solution would be to do what you currently are doing, and then later reverse the buffer, but this will require far more assignments than what is actually required.
The recommended way is to calculate the number of digits in your string, by doing this you'll know at what offset the end will be, and start assigning the least significant digit at that position.
How do I determine the number of digits of an integer in C?
The hack
Another alternative is having the recursive call modify the current value of our pointer, effectively making it assign the right value - at the right offset.
This example is mostly included because it's "fun", there are (as mentioned) other paths to walk.
#include <stdio.h>
void strnum_impl (int n, char ** str) {
if (n) {
strnum_impl (n/10, str);
**str = n%10 + '0';
(*str)++;
}
}
void strnum (int n, char * str) {
if (n == 0) { *str++ = '0'; }
else { strnum_impl (n, &str); }
*str = '\0'; /* null-terminate */
}
int main () {
char buf[256];
strnum (10240123, buf);
printf (">%s<\n", buf);
return 0;
}
>10240123<
As #Robert Harvey commented, as well as others, code is determining the least rather than the most significant digit and placing it in str[0].
It did look like fun to implement, so the below well copes with the entire range of int including INT_MIN and arbitrary sized int.
static char *strnum_helper(int n, char *str) {
str[0] = '0' - n%10;
if (n < -9) {
return strnum_helper(n/10, str - 1);
}
return str;
}
void strnum(int n, char *str) {
char buf[(sizeof n * CHAR_BIT)/3 + 3]; // Sized to any size int
if (n < 0) {
*str++ = '-';
}
else {
n = -n; // By using negative numbers, do not attempt -INT_MIN
}
buf[sizeof buf - 1] = '\0';
strcpy(str, strnum_helper(n, &buf[sizeof buf - 2]));
}
#Filip Roséen - refp pointed out the value of passing in a size. The above strnum() could be adjusted per a size limitation.

Using strtol to validate integer input in ANSI C

I am new to programming and to C in general and am currently studying it at university. This is for an assignment so I would like to avoid direct answers but are more after tips or hints/pushes in the right direction.
I am trying to use strtol to validate my keyboard input, more specifically, test whether the input is numeric. I have looked over other questions on here and other sites and I have followed instructions given to other users but it hasn't helped me.
From what I have read/ understand of strtol (long int strtol (const char* str, char** endptr, int base);) if the endptr is not a null pointer the function will set the value of the endptr to the first character after the number.
So if I was to enter 84948ldfk, the endptr would point to 'l', telling me there is characters other than numbers in the input and which would make it invalid.
However in my case, what is happening, is that no matter what I enter, my program is returning an Invalid input. Here is my code:
void run_perf_square(int *option_stats)
{
char input[MAX_NUM_INPUT + EXTRA_SPACES]; /*MAX_NUM_INPUT + EXTRA_SPACES are defined
*in header file. MAX_NUM_INPUT = 7
*and EXTRA_SPACES
*(for '\n' and '\0') = 2. */
char *ptr;
unsigned num=0; /*num is unsigned as it was specified in the start up code for the
*assignment. I am not allow to change it*/
printf("Perfect Square\n");
printf("--------------\n");
printf("Enter a positive integer (1 - 1000000):\n");
if(fgets(input, sizeof input, stdin) != NULL)
{
num=strtol(input, &ptr, 10);
if( num > 1000001)
{
printf("Invalid Input! PLease enter a positive integer between 1
and 1000000\n");
read_rest_of_line(); /*clears buffer to avoid overflows*/
run_perf_square(option_stats);
}
else if (num <= 0)
{
printf("Invalid Input! PLease enter a positive integer between 1
and 1000000\n");
run_perf_square(option_stats);
}
else if(ptr != NULL)
{
printf("Invalid Input! PLease enter a positive integer between 1
and 1000000\n");
run_perf_square(option_stats);
}
else
{
perfect_squares(option_stats, num);
}
}
}
Can anyone help me in the right direction? Obviously the error is with my if(ptr != NULL) condition, but as I understand it seems right. As I said, I have looked at previous questions similar to this and took the advice in the answers but it doesn't seem to work for me. Hence, I thought it best to ask for my help tailored to my own situation.
Thanks in advance!
You're checking the outcome of strtol in the wrong order, check ptr first, also don't check ptr against NULL, derference it and check that it points to the NUL ('\0') string terminator.
if (*ptr == '\0') {
// this means all characters were parsed and converted to `long`
}
else {
// this means either no characters were parsed correctly in which
// case the return value is completely invalid
// or
// there was a partial parsing of a number to `long` which is returned
// and ptr points to the remaining string
}
num > 1000001 also needs to be num > 1000000
num < 0 also needs to be num < 1
You can also with some reorganising and logic tweaks collapse your sequence of if statements down to only
a single invalid branch and a okay branch.
OP would like to avoid direct answers ....
validate integer input
Separate I/O from validation - 2 different functions.
I/O: Assume hostile input. (Text, too much text, too little text. I/O errors.) Do you want to consume leading spaces as part of I/O? Do you want to consume leading 0 as part of I/O? (suggest not)
Validate the string (NULL, lead space OK?, digits after a trailing space, too short, too long, under-range, over-range, Is 123.0 an OK integer)
strtol() is your friend to do the heavy conversion lifting. Check how errno should be set and tested afterward. Use the endptr. Should its value be set before. How to test afterward. It consume leading spaces, is that OK? It converts text to a long, but OP wants the nebulous "integer".
Qapla'
The function strtol returns long int, which is a signed value. I suggest that you use another variable (entry_num), which you could test for <0, thus detecting negative numbers.
I would also suggest that regex could test string input for digits and valid input, or you could use strtok and anything but digits as the delimiter ;-) Or you could scan the input string using validation, something like:
int validate_input ( char* input )
{
char *p = input;
if( !input ) return 0;
for( p=input; *p && (isdigit(*p) || iswhite(*p)); ++p )
{
}
if( *p ) return 0;
return 1;
}

C homework - string loops replacements

I know it's a little unorthodox and will probably cost me some downvotes, but since it's due in 1 hour and I have no idea where to begin I thought I'd ask you guys.
Basically I'm presented with a string that contains placeholders in + form, for example:
1+2+5
I have to create a function to print out all the possibilities of placing different combinations of any given series of digits. I.e. for the series:
[9,8,6] // string array
The output will be
16265
16285
16295
18265
18285
18295
19265
19285
19295
So for each input I get (number of digits)^(number of placeholders) lines of output.
Digits are 0-9 and the maximum form of the digits string is [0,1,2,3,4,5,6,7,8,9].
The original string can have many placeholders (as you'd expect the output can get VERY lengthly).
I have to do it in C, preferably with no recursion. Again I really appreciate any help, couldn't be more thankful right now.
If you can offer an idea, a simplified way to look at solving this, even in a different language or recursively, it'd still be ok, I could use a general concept and move on from there.
It prints them in different order, but it does not matter. and it's not recursive.
#include <stdlib.h>
#include <stdio.h>
int // 0 if no more.
get_string(char* s, const char* spare_chr, int spare_cnt, int comb_num){
for (; *s; s++){
if (*s != '+') continue;
*s = spare_chr[comb_num % spare_cnt];
comb_num /= spare_cnt;
};
return !comb_num;
};
int main(){
const char* spare_str = "986";
int num = 0;
while (1){
char str[] = "1+2+5";
if (!get_string(str, spare_str, strlen(spare_str), num++))
break; // done
printf("str num %2d: %s\n", num, str);
};
return 0;
};
In order to do the actual replacement, you can use strchr to find the first occurrence of a character and return a char * pointer to it. You can then simply change that pointer's value and bam, you've done a character replacement.
Because strchr searches for the first occurrence (before a null terminator), you can use it repeatedly for every value you want to replace.
The loop's a little trickier, but let's see what you make of this.

C - scanf() vs gets() vs fgets()

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)

Resources