Strict atoi/strtol function - c

In C when I use:
int x = 0;
char str[] = " \t123abc";
x = atoi(str);
printf("%d\n", str); //123
123 is printed. I would like to know if there is a 'strict' C function that returns 0 if the string isn't fully an integer. (I don't care about the number sign (always positive) and the base (always 10)).
Some examples:
" \t123abc" -> 0
" 123abc" -> 0
"123abc" -> 0
" 123 " -> 0
"123" -> 123
"123\n" -> 0
Currently I created a int sstoi (char *str) function to do it:
static const unsigned int pow10[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
int sstoi (char *str) {
int result = 0, length = strlen(str);
char c;
if (length > 10) return 0;
for (int i = 0; i < length; i++) {
c = str[i];
if (c < 48 || c > 57) return 0;
result += (c-48)*pow10[length-i-1];
}
return result;
}
I believe that it should be improved: can someone help me out?

You can at first check if all characters in string are number then use atoi:
if(strspn(str, "0123456789") == strlen(str))
{
x = atoi(str);
}
else
{
x = 0;
}

strtol() can set a pointer to the first invalid character in the string it scans, which would be the first character after the number. If you check that the first character is valid, you can use this pointer to see whether there were characters following the number or not.
int sstoi(char *s) {
char *ep; // to point to first char after the number
if (isdigit(*s)) { // make sure first char is a digit
// convert, and find first invalid char
int x = strtol(s, &ep, 10);
// return conversion if first invalid char was the
// terminating null
if (!(*ep))
return x;
}
return 0; // otherwise return 0
}

I could not find an inbuilt function which directly returns 0, it the input is wrong.
You can use the inbuilt function isdigit(char s) to check whether the given input is valid and if it's not then you can return 0.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
bool isValidNumber(char digitsArray[]){
bool isNumber = true;
for(int i=0; i < strlen(digitsArray); i++){
if(!isdigit(digitsArray[i])){
isNumber = false;
break;
}
}
return isNumber;
}
int getNumber(char digitsArray[]){
if(isValidNumber(digitsArray)){
return atoi(digitsArray);
}
return 0;
}
int main()
{
char str[] = "123\n";
int number = getNumber(str);
printf("Number is %d", number);
return 0;
}
Edit: The isValidNumber won't work if the char[] array contains a negative number.

Related

=CS50 PSET 2 CAESAR= How do I convert the key to digit? It gives me this error if I use atoi()

I'm having a problem with atoi() in the only_digits function. I asked on discord and they said that I am passing a char type arg to atoi() which doesn't work since atoi() only takes string or char * (array of char) as arguments. I don't get it. I'm confused with the difference of string and char. Aren't I passing argv[1] (which is a string) to only_digits? Which means inputKey is a string as well? So what do they mean that I am passing a char type arg to atoi()? How exactly do I make atoi() work? I'm stuck with this problem for 2 days now.
// Encrypts text using Caesar's cipher
// ci = (pi + k) % 26
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
bool only_digits (string inputKey);
char rotate (char plaintext[], int key);
int main(int argc, string argv[])
{
string p;
// Make sure program was run with just one command-line argument
if (argc != 2)
{
printf("Enter exactly one input\n");
return 1;
}
// Make sure every character in argv[1] is a digit (DOESN'T WORK)
/*else if (only_digits(argv[1]))
{
printf("Usage: ./caesar key\n");
return 1;
}*/
else
{
p = get_string("plaintext: ");
}
// Convert argv[1] from a string to an int
int k = atoi(argv[1]);
char c[strlen(p) + 1];
// Convert ASCII range down to a value from 0 to 25
// For each character in the plaintext: (DOESN'T WORK)
for (int i = 0, n = strlen(p); i <= n; i++)
{
// Rotate the character if it's a letter // ci = (pi + k) % 26
if (isalpha(p[i]))
{
if (isupper(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
else if (islower(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
}
}
printf("ciphertext: %s\n", c);
}
// Function to encrypt plaintext
/*char rotate (char plaintext[], int key)
{
char c[strlen(plaintext) + 1];
return c;
}*/
// Function to check if key is a digit (DOESN'T WORK)
bool only_digits (string inputKey)
{
int flag = 0;
for (int i = 0, n = strlen(inputKey); i < n; i++)
{
// Converts string input to int
int response = atoi(inputKey[i]);
// Check if it is a digit
if (!(isdigit(response)))
{
flag++;
}
}
if (flag != 0)
{
return false;
}
else
{
return true;
}
}
Strings in C are defined as a sequence of nonzero bytes (characters), followed by a null-terminating byte:
char str[] = "hello"; /* in memory: { 'h', 'e', 'l', 'l', 'o', '\0' } */
atoi (ASCII to integer) expects a proper null-terminated string (char *). You can not pass it a single char.
int number = atoi("1672387");
isdigit expects a single character.
int is_true = isdigit('5');
In your program inputKey[i] is a single character. You can test it directly with isdigit, there is no need to convert it to an integer representation beforehand.
You can also simply return early if you encounter a non-digit character.
bool only_digits(string inputKey) {
for (size_t i = 0, length = strlen(inputKey); i < length; i++)
if (!isdigit(inputKey[i]))
return false;
return true;
}
Note: size_t is the return type of strlen, and the most appropriate type for indexing memory.

Counting # of index of undefined char array in C

I'm trying to count the number of indexes of an undefined char array which is used as a parameter in the function.
I am already aware that if my array was fixed I can use "sizeof", which isn't the case here.
Attempt:
int counting(char *name3) {
int count = 0;
int i;
//I have no idea what to put as my condition nor do I believe
//I am approaching this situation correctly...
for (i = 0; i < sizeof(name3); i++) {
if (name3[i] != '\0') {
count++;
}
}
return count;
}
Then if it is run by the following code
int main(void) {
char *name = "Lovely";
int x = counting(name);
printf ("The value of x = %d", x);
Prints: The value of x = 0
Any help or pointers would be amazing. Thank you in advance.
In C, Every string ends with '\0' (Null Character)
You can iterate until you meet the Null Character
The example code would be like this
char* name = "Some Name";
int len = 0;
while (name[len] != '\0') {
len++;
}
Also, if it is a char pointer, not char array, sizeof(char*) will always return 4 in 32-bit application and return 8 in 64-bit application (the size of the 'pointer' itself - the memory address size)
#include <stdio.h>
int main()
{
int i=0;
char *name = "pritesh";
for(i=0;;i++)
{
if(name[i] == '\0')
{
break;
}
}
printf("%d", i);
return 0;
}
This should work
note: this might be syntactically incorrect as I have not had my hands on c since a long time

Calculating hamming distance by appending '0' to lesser length string

I have to find the hamming distance between two codes.
For example if I input:
a= 10
b= 1010
Automatically a should be made equal to the length of the string b by appending 0's.
So the input should become:
a=0010
b=1010
But I'm getting instead:
a = 001010
b = 1010
Here is my code:
#include<stdio.h>
#include<string.h>
void main()
{
char a[20],b[20],len1,len2,i,diff,count=0,j;
printf("Enter the first binary string\n");
scanf("%s",a);
printf("Enter the second binary string\n");
scanf("%s",b);
len1 = strlen(a);
len2 = strlen(b);
if(len1>len2)
{
diff = len1-len2;
for(i=0;i<len1;i++)
{
b[i+diff]=b[i];
}
j=i+diff;
b[j]='\0';
for(i=0;i<diff;i++)
{
b[i]='0';
}
}
else
{
diff = len2-len1;
for(i=0;i<len2;i++)
{
a[i+diff]=a[i];
}
j=i+diff;
a[j]='\0';
for(i=0;i<diff;i++)
{
a[i]='0';
}
}
printf("\nCodes are\n");
printf("a=%s\n",a);
printf("\nb=%s\n",b);
for(i=0;a[i]!='\0';i++)
{
if(a[i]!=b[i])
{
count++;
}
}
printf("hammung distance between two code word is %d\n",count);
}
Can anyone help me to fix this issue?
In your two for loop where you are moving the content of your old tab to the right to insert the zeros, you inverted the lengths.
First loop should be:
for(i=0;i<len2;i++)
{
b[i+diff]=b[i];
}
And second:
for(i=0;i<len1;i++)
{
a[i+diff]=a[i];
}
After trying it:
Codes are
a=0010
b=1010
hammung distance between two code word is 1
Also, the main function should return an int, not void. As stated in the comments, you should also change the type of your len1, len2, i, diff, count and j because you use them as number values, not as characters. You can for instance either use the int or size_t types for that.
int main()
{
char a[20],b[20];
int len1, len2, i, diff, count=0, j;
// Rest of your code
}
Here is a method that does not prepend zeros to the shortest binary string, and avoids the limitations of strtol() by comparing the elements of the string directly, starting with the last characters. The intricacies of using strtol() are traded for more complexity in handling the array indices. Note that care must be taken to avoid counting down to a negative value since size_t types are used. This method is not limited by the capacity of long types, but rather by size_t.
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[20], b[20];
printf("Enter first binary string: ");
scanf("%19s", a);
printf("Enter second binary string: ");
scanf("%19s", b);
size_t a_len = strlen(a);
size_t b_len = strlen(b);
size_t max_len = a_len > b_len ? a_len : b_len;
size_t hamming_dist = 0;
for (size_t i = 0; i < max_len; i++) {
if (a_len - i > 0 && b_len - i > 0) {
if (a[a_len - i - 1] == b[b_len - i - 1]) {
continue;
}
}
if ((a_len - i > 0 && a[a_len - i - 1] == '1') ||
(b_len - i > 0 && b[b_len - i - 1] == '1')) {
++hamming_dist;
}
}
printf("bstring_1: %s\n", a);
printf("bstring_2: %s\n", b);
printf("Hamming distance: %zu\n", hamming_dist);
return 0;
}
A way that doesn't need to pad one of the parameters with zeroes:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
char *a = "1010";
char *b = "10";
long unsigned int xorab;
unsigned int hammingDistance = 0;
xorab = strtoul(a, NULL, 2) ^ strtoul(b, NULL, 2);
while (xorab) {
hammingDistance += xorab & 1;
xorab >>= 1;
}
printf("%u\n", hammingDistance);
}
It uses strtoul to convert the binary strings to unsigned long int using a base 2, then you only have to use bitwise operators (xor, and, shift) to calculate the Hamming distance without to take care of the size difference.
Obviously, this way stops to work if you want to test binary strings with values greater than an unsigned long int.

Parsing a string into an array of integers in C

So now that I've figured out how to get what I want, I'm just hoping somebody can let me know a cleaner, less ridiculous way of achieving the same thing. I'm just learning C. Here was my approach.
int main()
{
// String of positive and negative integer values
// Numbers are never more than 2 digits
char TEMPS[256] = "1 -22 -8 14 5";
int N = 5;
int ints[N];
int i = 0;
int mult;
// Arbitrary number to identify that num is not yet in use
int num = 999;
int c = 0;
mult = (TEMPS[c] != 45) ? -1 : 1;
while(strcmp(&TEMPS[c], "\0") != 0)
{
if(TEMPS[c] == 32)
{
ints[i] = mult * num;
i++;
num = 999;
mult = (TEMPS[c + 1] == 45) ? -1 : 1;
}
else if((TEMPS[c] != 45) && (TEMPS[c] != 32))
{
if(num == 999)
{
num = TEMPS[c] - '0';
}
else
{
num = num * 10 + (TEMPS[c] - '0');
}
}
c++;
}
ints[i] = mult * num;
}
I would use strtol - here's a good site for how it works and examples
http://www.tutorialspoint.com/c_standard_library/c_function_strtol.htm
long int strtol(const char *str, char **endptr, int base)
Parameters
str -- This is the string containing the representation of an integral number.
endptr -- This is the reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value.
base -- This is the base, which must be between 2 and 36 inclusive, or be the special value 0.
Return Value
This function returns the converted integral number as a long int value, else zero value is r
I've included one example from the site.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[30] = "2030300 This is test";
char *ptr;
long ret;
ret = strtol(str, &ptr, 10);
printf("The number(unsigned long integer) is %ld\n", ret);
printf("String part is |%s|", ptr);
return(0);
}

Algorithm to parse an int from a string in one pass

I'm trying to write a function that parses an integer from a string representation.
My problem is that I don't know how to do this with one pass through the string. If I knew ahead of time that the input contained only characters in the range '0', '1', ..., '9' and that the string was of length n, I could of course calculate
character_1 * 10^(n-1) + character_2 * 10^(n-2) + .... + character_n * 10^0
but I want to deal with the general scenario as I've presented it.
I'm not looking for a library function, but an algorithm to achieve this in "pure C".
Here's the code I started from:
int parse_int (const char * c1, const char * c2, int * i)
{
/*
[c1, c2]: Range of characters in the string
i: Integer whose string representnation will be converted
Returns the number of characters parsed.
Exs. "2342kjsd32" returns 4, since the first 4 characters were parsed.
"hhsd3b23" returns 0
*/
int n = 0;
*i = 0;
while (c1!= c2)
{
char c = *c1;
if (c >= '0' && c <= '9')
{
}
}
return n;
}
Just as some of the comments and answers suggested, maybe a bit clearer: You have to "shift" the result "left" by multiplying it by 10 in every iteration before the addition of the new digit.
Indeed, this should remind us of Horner's method. As you have recognized, the result can be written like a polynomial:
result = c1 * 10^(n-1) + c2 * 10^(n-2) + ... + cn * 10^0
And this equation can be rewritten as this:
result = cn + 10*(... + 10*(c2 + 10*c1))
Which is the form this approach is based on. From the formula you can already see, that you don't need to know the power of 10 the first digit is to be multiplied by, directly from the start.
Here's an example:
#include <stdio.h>
int parse_int(const char * begin, const char * end, int * result) {
int d = 0;
for (*result = 0; begin != end; d++, begin++) {
int digit = *begin - '0';
if (digit >= 0 && digit < 10) {
*result *= 10;
*result += digit;
}
else break;
}
return d;
}
int main() {
char arr[] = "2342kjsd32";
int result;
int ndigits = parse_int(arr, arr+sizeof(arr), &result);
printf("%d digits parsed, got: %d\n", ndigits, result);
return 0;
}
The same can be achieved using sscanf(), for everyone that is fine with using the C standard library (can also handle negative numbers):
#include <stdio.h>
int main() {
char arr[] = "2342kjsd32";
int result, ndigits;
sscanf(arr, "%d%n", &result, &ndigits);
printf("%d digits parsed, got: %d\n", ndigits, result);
return 0;
}
The output is (both implementations):
$ gcc test.c && ./a.out
4 digits parsed, got: 2342
I think this is good solution to count parse character
int parse(char *str)
{
int k = 0;
while(*str)
{
if((*str >= '0') & (*str <= '9'))
break;
str++;
k++;
}
return k;
}
Here's a working version:
#include <stdio.h>
int parse_int (const char * c1, const char * c2, int * i)
{
/*
[c1, c2]: Range of characters in the string
i: Integer whose string representnation will be converted
Returns the number of characters parsed.
Exs. "2342kjsd32" returns 4, since the first 4 characters were parsed.
"hhsd3b23" returns 0
*/
int n = 0;
*i = 0;
for (; c1 != c2; c1++)
{
char c = *c1;
if (c >= '0' && c <= '9')
{
++n;
*i = *i * 10 + c - '0';
}
else
{
break;
}
}
return n;
}
int main()
{
int i;
char const* c1 = "2342kjsd32";
int n = parse_int(c1, c1+10, &i);
printf("n: %d, i: %d\n", n, i);
return 0;
}
Output:
n: 4, i: 2342

Resources