Convert string to integer recursively? - c

Here is a simple function that converts a string to an integer.
int str2int(char *str)
{
int ret = 0;
char *c;
for (c = str; (*c != '\0') && isdigit(*c); ++c)
ret = ret*10 + *c - '0';
return ret;
}
As an exercise, I'd like to write a recursive function that does the same thing. This is what I came up with.
int str2int2(char *c, int *i)
{
if (*c == '\0' || !isdigit(*c))
return *i;
*i = *i * 10 + *c - '0';
return str2int2(c + 1, i);
}
.
.
int i = 0;
.
... str2int2(str, &i);
Is there a way to write the recursive function without using the extra int* argument?

Sure, it's easy enough, but you need to write two functions, one with an accumulator, like this:
int str2int_rec(char *c, int accum)
{
if (!c || !*c || !isdigit(*c))
return accum;
return str2int_rec(c + 1, accum * 10 + (*c - '0'));
}
int str2int(char *c)
{
return str2int_rec(c, 0);
}

Well, you could hide the functionality from the person using the function. So you will have a function named int str2int(char *str) which will call int str2int(char *c, int *i) thereafter.
It's how I've done it in the past.

I think you may use horner scheme in order not to keep any 'i'.
You must reverse the string (yeah quit ugly) and then you can simply use:
int str2int (char* str)
{
if (*str+1)
{
return 10*str2int(str+1)+(*str-'0');
}
return 0;
}

One way could involve passing the length of the digit as an argument so we can read backwards efficiently:
int strtoi(char *c, size_t l)
{
return l ? c[l-1] - '0' + 10 * strtoi(c, l - 1) : 0;
}
Then call it like this:
int i = strtoi("432", 3);
Or:
char *c = "432";
int i = strtoi(c, strlen(c));
But it's not always optimal to bother with the length of a string. Plus, if a string has characters after a number, we'd have to factor that in manually, because this function won't do it for us. We can't (shouldn't) use strlen() inside our function to avoid having to pass arguments, because that can cause a considerable slowdown to recalculate the string's length every time. Surely there must be a way to do this from the beginning, even if we have to bring out the heavy artillery:
int strtoi(char *c)
{
if(!isdigit(*c)) return 0;
int i = strtoi(c + 1);
return i + pow(10, (int)(log(i + 1)/log(10)) + (i != 0)) * (*c - '0');
}
And no, that (int) cast isn't optional. Basically, all of that math calculates the power of 10 we need to multiply our current digit by, based on the number returned by the last recursive call.
I understand this is probably a learning exercise, but recursion is not the be-all, end-all of programming. In some languages, and for some tasks, it is what some, myself included, would call beautiful, but from the looks of it this is not one of those cases.

Related

While trying to write the recursive version of atoi, what is the meaning of itoa(n /10, s) and why is it advisable to avoid static int i = 0?

I'm sorry if my question is quite vague, because it is without context. So I was trying to solve a question: Write a recursive version of the function itoa(i) which converts an integer i into a string.
As I ran out of idea how to solve it, I started looking online to find solutions and I came across some of them which usually use this line: itoa(n/10, s);. For example, from this StackOverflow question: itoa recursively. I can't understand what it does to i.
So I went on and searched for more solutions and I found one that actually works, the program looks like this:
#include <stdio.h>
char *itoa(int n, char s[]);
int main()
{
char number[100];
printf("-90 to string = %s\n", itoa(-90, number));
return 0;
}
char *itoa(int n, char s[])
{
static int i = 0;
if (n < 0) {
s[i++] = '-';
n = -n; /* does not work for largest negative number in two complement */
}
if (n / 10)
itoa(n /10, s);
s[i++] = n % 10 + '0';
s[i] = '\0';
return s;
}
Problem is, according to the solutions I found on other websites, people said that we should avoid using static int i. I did not read why we should do so because I don't know how static works so I don't know if this program is fine or needs improvements.
Your function pretty much almost right, that is for a recursive method. If you were going to parse the digit to string backward, it is right. Otherwise, I just did a couple fix.
For parsing digit to string, the digits that are being parsed are from the right digits to left digits as the remainder is what being used. Thus, when storing those into a string, we will need to go from high to low indexes. If we use remainders for parsing, we will not know the length of the number that is being parsed. Thus, in most parse cases there will be some extra spaces at the beginning of your string or char array.
For using the static i, you can pass a version of it around but it would make it harder to use as you would need to know to always have to pass i at 11. "i" is at 11 because the maximum digits for an int is 10(digits) + 1 sign and the 12th character which not counted by "i" is the null char. To make it easier to use the function, I configured the third parameter to be a void pointer. However, do not pass it an actual pointer, pass it a NULL. When it see NULL as the third parameter, it know that, that is the first call.
#include <stdio.h>
#include <string.h>
char *itoa(int n, char s[], void * );
int main()
{
char number[100] = {0};
printf("-90 to string = %s\n", itoa(154, number, NULL));
printf("-15 to string = %s\n", itoa(-15, number, NULL));
printf("-2147483648 to string = %s\n", itoa(-2147483648, number, NULL));
return 0;
}
// The reason why I pass a void pointer is because
// instead of passing the value is because it easier to use function without needing to know that the string have to go from right left.
// When you first call it just use NULL as the third parameter. Anything else can ruin it.
char *itoa(int n, char s[], void * firstCall )
{
static int i;
if ( firstCall == NULL ) {
i = 11;
s[11] = 0;
}
int neg = 0;
if (n < 0) {
if ( n == -2147483648 ) {
strcpy(s, "-2147483648");
return s;
}
neg=1;
n = -n; /* does not work for largest negative number in two complement */
}
s[--i] = (n % 10) ^ 48;
if ( n / 10 ) itoa(n / 10, s, s);
if ( neg == 1 ) s[--i] = '-';
return &s[i];
}

How to convert a string to double floating-point value?

sorry if the title is confusing, I just need some experienced programmers to attempt to clarify something for me. So one of my homework questions asks me this (the language is c):
Write a function that receives a string and returns a double floating-point value. The fucntion declaration would look like this
double convertFloat(char s[]);
Do not use the strtol() function or any other standard c library function. Write your own!... Note that the input string could have any of the following sample formats: "1.34", "-1.4554", "6".
I am just not sure how to approach this because I am not sure what is being asked here. If I had to write a function to find a square root or something like that I could do it no problem but it seems that I have to take strings that are all numbers and convert them to floats... just not sure where to start and googling similar things has yielded no results.
Thank you all in advance.
- Davey
Start by writing
unsigned int convertUnsignedInt(const char *s);
// e.g. convertUnsignedInt("42") == 42
It's a bit simpler because you don't have to handle negative numbers or fractions, but it shows the general principle.
Here is the complete code to your problem. The code is understandable. Ask if you have any doubts regarding it.
#include <stdio.h>
int power(int n, int m)
{
if (m == 1)
return n;
else
return n * (power(n, m - 1));
}
int getLength(char s[])
{
int i = 0;
for(i = 0; s[i] != '\0'; i++);
return i;
}
double convertFloat(char s[])
{
int len = getLength(s);
int dotpos = 0;
double result = 0.0f;
int n = 0, flag = 0;
if(s[0] == '-')
{
n = 1;
flag = 1;
}
for (; n < len; n++)
{
if (s[n] == '.')
{
dotpos = len - n - 1;
}
else
{
result = result * 10 + (s[n] - '0');
}
}
result /= power(10, dotpos);
if(flag)
return result*-1;
return result;
}
int main()
{
char str[] = "126433.47";
printf("%f", convertFloat(str));
}

Checking how much times a character occurs in a string with a recursive function

So, I have to write down a recursive function for checking how much times a character (c) occurs in a string (array) : note that the function MUST BE recursive. To be honest this is the hardest thing I've had to face since I started, so this is taking very long :| Here is the code (language is C) :
#include <stdio.h>
#include <time.h>
#define MAX 5
int charOccur (char [], int);
int main() {
char array[MAX+1]={'a', 'x', 'c', 'f', 'r'};
charOccur (array, MAX);
return 0;
}
int charOccur (char arr[], int dim){
int i, flag=0;
if (arr[0] == 'c'){
flag = 1;
return flag;
} else {
for (i=1; i<dim; i++){
if (arr[i] == 'c'){
flag++;
charOccur (arr, dim);
}
} return flag;
}
}
int occur(char *s, char c)
{
if (!*s) // if (*s == '\0')
return (0); // s is empty, do the character we're looking for does not exist
else if (*s == c)
return (1 + occur(s + 1, c));
else
return (occur(s + 1, c));
}
In the second case, we found our character, so we count 1 plus the rest of the input fed in our recursive function.
In the third case, the character pointed by s is neither '\0' nor c, so we keep going until we reach the end of the string.
In boths case, we use pointer arithmetic (s + 1), to change the character which is being pointed.
You should read a bit on memoization (it's not a typo). This wikipedia link is a good starting point; a more practical example is this one, which says:
Memoization means recording the results of earlier calculations so that we don’t have to repeat the calculations later.
In other words, in your code you might consider passing a counter to your function to store the result of the computation, before passing it to itself for the next recursion.
The example is shown in Ruby - it will help you understand the concept, rather than copy-pasting it as a solution.
And don't forget that in order to understand recursion, you must first understand recursion.
Consider a recursion that divides by 2 in each call. It does not reduce the number of calls, but limits the call depth to O(log2(n)).
#include <stdio.h>
#include <string.h>
static size_t Occurrence_helper(const char *s, size_t length, int ch) {
if (length > 1) {
size_t left = length / 2;
size_t right = length - left;
return Occurrence_helper(s, left, ch)
+ Occurrence_helper(s + left, right, ch);
} else if (length > 0) {
return *s == ch;
} else {
return 0;
}
}
size_t Occurrence(const char *s, int ch) {
return Occurrence_helper(s, strlen(s), ch);
}
Sample
int main(void) {
int ch = 'y';
const char *s = "xyzzy";
printf("'%c' occurs %zu times in \"%s\".\n", ch, Occurrence(s, ch), s);
return 0;
}
// Ouptut
'y' occurs 2 times in "xyzzy".
// 01 ) where 'c' is a constant
int charOccur (char arr[], int dim){
if(!dim) return 0;
dim--;
return ('c'==arr[dim])+charOccur (arr,dim);
}
// 02 ) passing c as a second parameter
int charOccur (char arr[],char c , int dim){
if(!dim) return 0;
dim--;
return (c==arr[dim])+charOccur (arr,c,dim);
}

C Library function for converting a string of hex digits to ints?

I have a variable length string where each character represents a hex digit. I could iterate through the characters and use a case statement to convert it to hex but I feel like there has to be a standard library function that will handle this. Is there any such thing?
Example of what I want to do. "17bf59c" -> int intarray[7] = { 1, 7, 0xb, 0xf, 5, 9, 0xc}
No, there's no such function, probably because (and now I'm guessing, I'm not a C standard library architect by a long stretch) it's something that's quite easy to put together from existing functions. Here's one way of doing it decently:
int * string_to_int_array(const char *string, size_t length)
{
int *out = malloc(length * sizeof *out);
if(out != NULL)
{
size_t i;
for(i = 0; i < length; i++)
{
const char here = tolower(string[i]);
out[i] = (here <= '9') ? (here - '\0') : (10 + (here - 'a'));
}
}
return out;
}
Note: the above is untested.
Also note things that maybe aren't obvious, but still subtly important (in my opinion):
Use const for pointer arguments that are treated as "read only" by the function.
Don't repeat the type that out is pointing at, use sizeof *out.
Don't cast the return value of malloc() in C.
Check that malloc() succeeded before using the memory.
Don't hard-code ASCII values, use character constants.
The above still assumes an encoding where 'a'..'f' are contigous, and would likely break on e.g. EBCDIC. You get what you pay for, sometimes. :)
using strtol
void to_int_array (int *dst, const char *hexs)
{
char buf[2] = {0};
char c;
while ((c = *hexs++)) {
buf[0] = c;
*dst++ = strtol(buf,NULL,16);
}
}
Here's another version that allows you to pass in the output array. Most of the time, you don't need to malloc, and that's expensive. A stack variable is typically fine, and you know the output is never going to be bigger than your input. You can still pass in an allocated array, if it's too big, or you need to pass it back up.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* str of length len is parsed to individual ints into output
* length of output needs to be at least len.
* returns number of parsed elements. Maybe shorter if there
* are invalid characters in str.
*/
int string_to_array(const char *str, int *output)
{
int *out = output;
for (; *str; str++) {
if (isxdigit(*str & 0xff)) {
char ch = tolower(*str & 0xff);
*out++ = (ch >= 'a' && ch <= 'z') ? ch - 'a' + 10 : ch - '0';
}
}
return out - output;
}
int main(void)
{
int values[10];
int len = string_to_array("17bzzf59c", values);
int i = 0;
for (i = 0; i < len; i++)
printf("%x ", values[i]);
printf("\n");
return EXIT_SUCCESS;
}
#include <stdio.h>
int main(){
char data[] = "17bf59c";
const int len = sizeof(data)/sizeof(char)-1;
int i,value[sizeof(data)/sizeof(char)-1];
for(i=0;i<len;++i)
sscanf(data+i, "%1x",value + i);
for(i=0;i<len;++i)
printf("0x%x\n", value[i]);
return 0;
}

Is there a strtol equivalent that does not require a null-terminated string?

Is there a standard C function similar to strtol which will take a char* and a length for a non-null-terminated string?
I know that I could copy out the string into a null-terminated region, but for efficiency reasons that is undesirable.
No such function in the standard library. You will either have to use the temporary buffer method, or write your own function from scratch.
To answer your question: no, there is no standard function, but it is simple enough to write your own:
#include <stdio.h>
#include <ctype.h>
int natoi(char *s, int n)
{
int x = 0;
while(isdigit(s[0]) && n--)
{
x = x * 10 + (s[0] - '0');
s++;
}
return x;
}
int main(int argc, char*argv[])
{
int i;
for(i = 1; i < argc; i++)
printf("%d: %d\n", i, natoi(argv[i], 5));
}
strntol is probably what you're after... it's not standard C, though.
If you're that pressed for efficiency, you can probably motivate the time to write and debug your own.
But: just do it with a copy; you probably have an upper bound for how long the string can be (a decimal numeral that fits in a long has a strict upper bound on its maximum length), so you can have a static buffer. Then profile your entire application, and see if the copying/conversion really is a bottleneck. If it really is, then you know you need to write your own.
Here's a rough (untested, browser-written) starting point:
long limited_strtol(const char *string, size_t len)
{
long sign = 1;
long value = 0;
for(; len > 0 && *string == '-'; string++, len--)
sign *= -1;
for(; len > 0 && isdigit(*string); string++, len--)
{
value *= 10;
value += *string - '0';
len--;
string++;
}
return sign * value;
}

Resources