1

I would like to convert a number, let's say, 1024 or 2345787654 into english words, such that for 1024 it should print one thousand twenty four etc.

However, my code gives me segmentation fault. I tried to run it with gdb but is suggests that the problem is inside my_strcat function. However, I do not see any problem with this function. Please, help.

#include <stdlib.h>
#include <string.h>

const char *digits[] = { NULL, "one ", "two ", "three ", "four ", "five ", "six ", "seven ", "eight ", "nine " };
const char *tens[] = { NULL, "ten ", "twenty ", "thirty ", "forty ", "fifty ", "sixty ", "seventy ", "eighty ", "ninety " };
const char *teens[] = { "ten ", "eleven ", "twelve ", "thirteen ", "fourteen ", "fifteen ", "sixteen ", "seventeen ", "eighteen ", "nineteen " };
const char *scales[] = { "", "thousand ", "million ", "billion " };

char *my_strcat ( char **dest, const char * src)
{
    char *tab = malloc ( sizeof ( char) * (strlen ( *dest) + strlen ( src) + 1));
    if ( NULL == tab)
        return NULL;
    strcpy ( tab, *dest);
    strcat ( tab, src);
    free ( *dest);
    *dest = malloc ( sizeof ( char) * ( strlen ( tab) + 1));
    strcpy ( *dest, tab);
    return tab;
}

char * LongToEnglish(unsigned long x)
{
    switch(x)
    {
    case 0:
        return "Zero";
    case 1:
        return "One";
    case 2:
        return "Two";
    case 3:
        return "Three";
    case 4:
        return "Four";
    case 5:
        return "Five";
    case 6:
        return "Six";
    case 7:
        return "Seven";
    case 8:
        return "Eight";
    case 9:
        return "Nine";
    case 10:
        return "Ten";
    case 11:
        return "Eleven";
    case 12:
        return "Twelve";
    case 13:
        return "Thirteen";
    case 14:
        return "Fourteen";
    case 15:
        return "Fifteen";
    case 16:
        return "Sixteen";
    case 17:
        return "Seventeen";
    case 18:
        return "Eighteen";
    case 19:
        return "Nineteen";
    case 20:
        return "Twenty";
    case 30:
        return "Thirty";
    case 40:
        return "Forty";
    case 50:
        return "Fifty";
    case 60:
        return "Sixty";
    case 70:
        return "Seventy";
    case 80:
        return "Eighty";
    case 90:
        return "Ninety";
    case 100:
        return "One Hundred";
    case 1000:
        return "One Thousand";
    case 1000000:
        return "One Million";
    case 1000000000:
        return "One Billion";
    }
    // less than 100
    for (long i = 1; i <= 9; i ++)
    {
        long j = i * 10;
        if ((x >= j) && (x < j + 10))
        {
            long r = x - j;

            if(r > 0)
                return my_strcat(my_strcat(*LongToEnglish(j), " "), LongToEnglish(r));
            else
                return my_strcat(*LongToEnglish(j), "");
        }
    }
    // less than 1000
    for (long i = 1; i <= 9; i ++)
    {
        long j = i * 100;
        if ((x >= j) && (x < j + 100))
        {
            long r = x - j;

            if(r > 0)
                return my_strcat(my_strcat(LongToEnglish(i), " Hundred "), LongToEnglish(r));
            else
                return my_strcat(LongToEnglish(i), " Hundred");
        }
    }
    // less than 10000
    for (long i = 1; i <= 9; i ++)
    {
        long j = i * 1000;
        if ((x >= j) && (x < j + 1000))
        {
            long r = x - j;
            if(r > 0)
                return my_strcat(my_strcat(LongToEnglish(i), " Thousand "), LongToEnglish(r));
            else
                return my_strcat(LongToEnglish(i), " Thousand");
        }
    }
    // Million
    for (long i = 1; i <= 9; i ++)
    {
        long j = i * 1000000;
        if ((x >= j) && (x < j + 1000000))
        {
            long r = x - j;
            if(r > 0)
                return my_strcat(my_strcat(LongToEnglish(i), " Million "), LongToEnglish(r));
            else
                return my_strcat(LongToEnglish(i), " Million");
        }
    }
    // Billion
    for (long i = 1; i <= 4; i ++)
    {
        long j = i * 1000000000;
        if ((x >= j) && (x < j + 1000000000))
        {
            long r = x - j;
            if(r > 0)
                return my_strcat(my_strcat(LongToEnglish(i), " Billion "), LongToEnglish(r));
            else
                return my_strcat(LongToEnglish(i), " Billion");
        }
    }
    // Divide the number into 3-digit groups from left to right
    char* output = "";
    long cnt = 0;
    while (x > 0)
    {
        long y = x % 1000;
        x /= 1000;
        if (y > 0)   // skip middle-chunk zero
        {
            char * t = "";
            if (cnt == 1) t = " Thousand ";
            if (cnt == 2) t = " Million ";
            if (cnt == 3) t = " Billion ";
            output = my_strcat(my_strcat(LongToEnglish(y), t), output);
        }
        cnt ++;
    }

    return (output);
}

char* numberToWords(int num)
{
    return LongToEnglish(num);
}

int main(int argc, char **argv)
{
    char *dst = NULL;
    dst = malloc ( sizeof ( char) * 10000000);

    unsigned long long n = 122334;
    dst = numberToWords(n);

    printf("%s", dst);
    free(dst);

    return 0;
}
Zim84
  • 3,404
  • 2
  • 35
  • 40
yak
  • 3,770
  • 19
  • 60
  • 111
  • At `return my_strcat(my_strcat(*LongToEnglish(j), " "), LongToEnglish(r));` and the line below it, I don't think you want to deference there. All the other ones don't deference. – Thomas Jager Jun 05 '19 at 12:19
  • 1
    Actually, there are many type issues. You have `char *` passed as `char **` arguments and `char` passed as `char *` arguments. – Thomas Jager Jun 05 '19 at 12:22
  • 4
    To expand on Thomas’ comment: **You must fix your compiler warnings first**. These “warnings” are actually errors, which you are ignoring. *After* that we can start talking about runtime errors. – Konrad Rudolph Jun 05 '19 at 12:24
  • Take a look at [https://stackoverflow.com/questions/51204004/convert-numbers-to-words-with-vba/51204358] where the same question was asked using VBA instead of C – pjaj Jun 05 '19 at 12:44
  • There is another solution in C here [https://www.geeksforgeeks.org/convert-number-to-words/] you just need to google your question. – pjaj Jun 05 '19 at 12:47
  • This code has tons of warnings even when compiling without extra flags in gcc. Fix those warnings first. – klutt Jun 05 '19 at 13:37

2 Answers2

2

There are other problems in your code, I tell just one. When input is n=3 in main, numberToWords returns "Three" and you try to call free("Three"), etc.

You return a static string sometimes and try to free it for this particular case.

alinsoar
  • 15,386
  • 4
  • 57
  • 74
1

The task is for groups of thousands allways the same. So you can do it much less complicated. The string handling might be optimized...

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

const char *digits[] = { NULL, "one ", "two ", "three ", "four ", "five ", "six ", "seven ", "eight ", "nine ", "ten ", "eleven ", "twelve ", "thirteen ", "fourteen ", "fifteen ", "sixteen ", "seventeen ", "eighteen ", "nineteen " };
const char *tens[] = { NULL, "ten ", "twenty ", "thirty ", "forty ", "fifty ", "sixty ", "seventy ", "eighty ", "ninety " };
const char *scales[] = { "", "thousand ", "million ", "billion " };

char *long2words(long x, int grp) {
    char *buf = malloc(4096), *bp;    
    int e,t,h;

    *buf='\0';
    e = x%10;
    t = (x/10)%10;
    h = (x/100)%10;
    x /=1000;
    if(x!=0) {
        strcat(buf, bp=long2words(x,grp+1));
        free(bp);
    }
    if(h!=0) {
        strcat(buf, digits[h]);
        strcat(buf,"hundred ");
    }
    if(t<2) strcat(buf, digits[t*10+e]);
    else {
        strcat(buf, tens[t]);
        strcat(buf, digits[e]);
    }
    strcat(buf, scales[grp]);

    return buf;
}
int main()
{
    printf(long2words(102410241024,0));

    return 0;
}
Holger
  • 899
  • 2
  • 7
  • 12