收录日期:2020/10/28 10:56:13 时间:2010-09-07 02:17:02 标签:c

Whilst reading through K&R, I came across the integer to string function. I gave it a quick read, and decided to implement it myself, but instead of printing, it updates a character array.

Here is what I have

void inttostr(int number, char str[]) {
    static int i;  
    if (number / 10) {
        inttostr(number / 10, str); 
    }       
    str[i++] =  number % 10 + '0';      
}

It seemed to work for the few integers I gave it, but I have some questions.

  1. I haven't explicitly included the nul byte \0 at the end, so why does the string work fine when printed with printf("%s\n", str);?
  2. I don't think I'm very good at thinking recursively. When I try and step through the program in my mind, I lose track of what is still awaiting execution. Is there a better way of seeing what is happening internally, to help me learn?
  3. Any other suggestions on the code?

I'm using Xcode.

This is not homework. I'm just learning.

Thanks!

You're correct that you're never writing NUL, which is a bug.

In general, you don't have to think through the entire solution. You just have to make sure every step is correct. So in this case, you say:

1 . inttostr(number / 10, str);

will take care of all but the last digit.

2 . Then I will take care of the last one.

You can trace what's happening, though. For e.g. 54321 it looks like:

inttostr(54321, str); // str = ...;
inttostr(5432, str); // str = ...;
inttostr(543, str); // str = ...;
inttostr(54, str); // str = ...;
inttostr(5, str); // str = ...;
str[0] = '5'; // str = "5...";
str[1] = '4'; // str = "54...";
str[2] = '3'; // str = "543...";
str[3] = '2'; // str = "5432...";
str[4] = '1'; // str = "54321...";

Note that when you don't return from any of the functions until you write the first character, then you return in the opposite order from the calls.

The ... signifies that you haven't NUL-terminated. Another issue is that you're using a static variable, so your code isn't reentrant; this means it breaks in certain scenarios, including multi-threading.

To address the reentrancy and NUL issue, you can do something like the code below. This creates a helper function, and passes the current index to write.

void inttostr_helper(int number, char str[], int *i)
{
    if (number / 10) {
        inttostr_helper(number / 10, str, i); 
    }       
    str[(*i)++] =  number % 10 + '0';
    str[*i] = '\0';
}

void inttostr(int number, char str[])
{
  int i = 0;
  inttostr_helper(number, str, &i);
}

EDIT: Fixed non-static solution.

I am impressed of the creativity to use recursive, despite that it is not necessary. I think the code should remove statically-allocated i variable because this variable will persist through calls. So the second time you use this function from your code, e.g. from main(), it will not be initiated and will be the same value from previous call. I would suggest using return value as follow:

int inttostr(int number, char *str) {
   int idx = 0;
   if (number / 10) {
        idx = inttostr(number / 10, str); 
   }       
   str[idx++] =  number % 10 + '0';
   return idx;
}

1, Your compiler (especially in debug mode) may have filled str with 0. Unix does this if you allocate memory with new() - But don't rely on this, either set the first byte to \0 or memset everything to 0

2, paper + pencil. Draw a table with each variable across the top and time down the side.

3, Write the simplest, longest version first, then get clever.

  • I haven't explicitly included the nul byte \0 at the end, so why does the string work fine when printed with printf("%s\n", str);?

how is the original char array declared when you call your function the first time? if it is a static char array then it will be filled with 0's and that would explain why it works, otherwise its just "luck"

  • I don't think I'm very good at thinking recursively. When I try and step through the program in my mind, I lose track of what is still awaiting execution. Is there a better way of seeing what is happening internally, to help me learn?

honestly, I am not sure if anybody is good in thinking recursively :-)

Did you try drawing the execution step by step?