0

I have a issue with my number to string implemention. For some reason I keep getting 000 on my terminal even though. I couldn't find a solution, what is the potantial issue here? Im now sure my code is broken but don't really see the problem.

#include <stdio.h> 
#include <stdlib.h>
#include <math.h>

/* public domain code feel free to use as what you wish, no warranties given*/
char finddigits(unsigned n) {
    char base = 6;
    unsigned tester = 100000;
    while(base % tester != 0) { 
        base--;
        /* inefficient but works for now */
        switch(tester) {
            case 100000:
                tester = 10000;
                break;
            case 10000:
                tester = 1000;
                break;
            case 1000:
                tester = 100;
                break;
            case 100:
                tester = 10;
                break;
            case 10:
                tester = 1;
                break;
        }
    }
    return base;
}

char* num2str(unsigned n) {
    char size = finddigits(n);
    char* tempbuf = malloc(size);
    *tempbuf = 48 + (n / pow(10, size));
    for(unsigned int i = 1; i < size; i++) 
        *(tempbuf + i) = 48 + (n % (10 * i));
    return tempbuf;
}

int main(int argc, char* argv[]) {
    int numbr = 210;
    printf("%s \n", num2str(numbr));
    /* expected 210 on string got 000 */
    return 0;
}
drk1
  • 65
  • 11
  • 1
    `findBase` always returns 3? It doesn't use its argument `n`. – Paul Hankin Sep 26 '22 at 16:14
  • What is `findbase` supposed to do? – Jabberwocky Sep 26 '22 at 16:17
  • Where are your `#include`s?. They actually do matter a lot. – Jabberwocky Sep 26 '22 at 16:18
  • `n % (10 * i)` is also wrong, and you need to null-terminate the string. You can use `sprintf(buff, "%u", n);` to convert a number to a string. – Paul Hankin Sep 26 '22 at 16:19
  • `sprintf` is the best solution, but it's OK to do this as an exercise. – Jabberwocky Sep 26 '22 at 16:22
  • 1
    Don't hard-code the ASCII code `48`, use the char literal `'0'` – Barmar Sep 26 '22 at 16:25
  • 2
    I think it would be worth understanding why you think "I'm sure my code is correct" when faced with clear and incontrovertible evidence that it's not correct. – jarmod Sep 26 '22 at 16:26
  • Start fixing `fineBase`, we have told you why it doesn't work. Also answer the comment that asks what `findBase is supposed to do. – Jabberwocky Sep 26 '22 at 16:35
  • @Jabberwocky code wasnt in english originally and it was badly translated, it is a function susposed to tell how many digits in a number for example 20 would give 2 1000 would give 4 – drk1 Sep 26 '22 at 16:37
  • 1
    Style note: `*(tempbuf + i) = 48 + (n % (10 * i));` is a really awkward way to write: `tempbuf[i] = '0' + (n % (10 * i));` – Chris Sep 26 '22 at 18:02
  • Does this answer your question? [How to convert an int to string in C?](https://stackoverflow.com/questions/8257714/how-to-convert-an-int-to-string-in-c) – Chris Sep 26 '22 at 19:57

4 Answers4

3

You just want num2str to return the digit string for n.

A few issues:

  1. finddigits is supposed to calculate the number of digits in n. But, [if it works at all], it uses an algorithm I've never seen.
  2. finddigits isn't needed in num2str as num2str can be [much] simpler by filling the buffer in the reverse direction.
  3. num2str is too complicated.
  4. Calling num2str from printf leaks memory from the num2str call to malloc

Here's a refactored version:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

char
finddigits(unsigned n)
{
    int count = 0;

    if (n == 0)
        count = 1;

    for (;  n != 0;  n /= 10, ++count);

    return count;
}

char *
num2str(unsigned n)
{
    static char buf[100];
    char *dst = &buf[sizeof(buf) - 1];

    // add string terminator
    *dst-- = 0;

    // we must always output a 0
    if (n == 0)
        *dst-- = '0';

    // work backwards in the array
    for (;  n != 0;  n /= 10, --dst)
        *dst = (n % 10) + '0';

    // point to first digit in string
    dst += 1;

    return dst;
}

void
dotest(unsigned n)
{

    printf("n=%u '%s'\n",n,num2str(n));
}

int
main(int argc, char *argv[])
{

    dotest(210);
    dotest(0);
    dotest(12345);

    return 0;
}

Here's the program output:

n=210 '210'
n=0 '0'
n=12345 '12345'
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • I changed 210 to -210 and ran your code... Output was not what I expected. – Fe2O3 Sep 26 '22 at 22:29
  • @Fe2O3 As we often ask OPs, what was your expected output? I assume you got `4294967086` because `n` is `unsigned`. I think this is deliberate on the part of the instructor because (e.g.) the next step/problem is to use `int` and the special case for `INT_MIN` – Craig Estey Sep 27 '22 at 14:04
1

The computer does what you told it to do, which is to say, it does complete nonsense.

finddigits(210) returns 1, because 6 % 100000 isn't 0 (it's 6), 5%10000 isn't 0 (it's 5), 4 % 1000 isn't 0 (it's 4), 3 % 100 isn't 0 (it's 3), 2 % 10 isn't 0 (it's 2), but 1 % 1 is 0 so the loop stops and the function returns 1.

Then, num2str allocates 1 byte. In this 1 byte, it sets the first byte to 48 + (210 / 10) which is 69, ASCII code for the letter E. Since size is 1 the loop doesn't run at all and num2str returns this allocation. When you print it, it prints the letter E - possibly with more gibberish after it since the string is not terminated, although for me it just printed E.

I have no idea how you managed to get 000.

You need to write code that tells the computer to do what you want it to do. When you can't get it to do what you want it to, for one part of the code, don't just skip that part of the code and go onto the next one. It all has to be right or it won't work.

user253751
  • 57,427
  • 7
  • 48
  • 90
  • 3
    This answer does a great job of explaining what was done wrong, but offers no suggestions on a correct algorithm. Doing so would vastly improve this answer. As it is, it feels more like a long comment than an answer. – Chris Sep 26 '22 at 16:54
  • @Chris indeed, but pedantically, the question was "why does it return this?" :) – user253751 Sep 26 '22 at 16:56
  • @Chris In this case, explaining what was done wrong is a fine and sufficient answer, I think. The OP's code is, sad to say, beyond repair. The OP needs to throw that code away and start form scratch. But converting an integer to a string is *such a common problem* that there are literally millions of examples out there, you can practically find them at random while stumbling down alleyways in the dark. I hardly think user253751 needs to pick one of those millions and recommend it to the OP in this case. – Steve Summit Sep 26 '22 at 17:36
  • @Chris I don't like Craig Estey's answer either, which does show working code - IMO people who ask questions like this need to learn by practice, not by copy-pasting working code. Hence I often try to guide them in the direction of realizing the problem themselves. In this case the code is not really salvageable but I hope to at least explain why it doesn't work. – user253751 Sep 26 '22 at 17:44
  • I agree about providing completely working code, and did not mean to suggest the inclusion of that. – Chris Sep 26 '22 at 17:45
0

Mathematics is also "public domain". Here are two versions of one of your functions, shown with a main() that tests both versions with several values.

Don't convert a signed integer value to unsigned for no particular reason. If you need/want the absolute value of a (possibly) negative number, C provides a function to achieve that.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int finddigits1( int n ) {
    int count = n == 0; // ensure 0 is counted as 1 digit

    while( n ) count++, n /= 10;

    return count;
}

int finddigits2( int n ) {
    // log of zero is undefined
    return ( n == 0 ) ? 1 : (int)log10(abs(n))+1;
}

char *num2str( int n, char buf[] ) {
    printf( "finddigits1( %d ) counted %d\n", n, finddigits1( n ) );
    printf( "finddigits2( %d ) returns %d\n", n, finddigits2( n ) );

    strcpy( buf, "Hello world!" ); // Left as an exercise to fix your own code

    return buf; // returning allows direct usage by caller
}

int main() {
    int tests[] = { 123, -123, 0, 100, 54321 };
    char buf[ 30 ]; // better to pass large buffer to function than use malloc()

    for( int i = 0; i < sizeof tests/sizeof tests[0]; i++ ) {
        int n = tests[i];
        printf( "n = %d '%s'\n", n, num2str( n, buf ) );
    }

    return 0;
}
finddigits1( 123 ) counted 3
finddigits2( 123 ) returns 3
n = 123 'Hello world!'
finddigits1( -123 ) counted 3 // NB: Account for negative sign!
finddigits2( -123 ) returns 3
n = -123 'Hello world!'
finddigits1( 0 ) counted 1
finddigits2( 0 ) returns 1
n = 0 'Hello world!'
finddigits1( 100 ) counted 3
finddigits2( 100 ) returns 3
n = 100 'Hello world!'
finddigits1( 54321 ) counted 5
finddigits2( 54321 ) returns 5
n = 54321 'Hello world!'
Fe2O3
  • 6,077
  • 2
  • 4
  • 20
-1

If you're trying to convert a number to a string, why not just use sprintf()? See here:

How to convert an int to string in C?

Mark J. Bobak
  • 13,720
  • 6
  • 39
  • 67