Home > Enterprise >  why is my program ignoring parts of my code (in c)
why is my program ignoring parts of my code (in c)

Time:11-29

I've written this piece of code to see if I could convert simple numbers from decimal to, for example, binary numbers per base (e.g. binary base = 2) I know it wouldn't really be the correct number for hex, or anything above base = 9 for that matter, (that's why I added a space in printf (temp[I]) so I could see the separate base^index-1 ) but here's my problem: after compiling and running it, I can enter decimal and base, then it prints those 2 and then... nothing. It's ignoring convert(); and for(){printf} completely for some reason. PS: the reason I calloc exactly decimal times sizeof int is because maybe some one types base = 1 yk just in case. Also wouldn't really matter, as I count the length of the array anyway per int counter, right?

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

void convert(int decimal, int base, int counter, int temp[])
{
    int remainder;
    int quotient;
    int i = 0;
    while (decimal > 0)
    {
        remainder = decimal % base; // remainder is stored
        quotient = (decimal - remainder) / base; //quotient is stored
        decimal = quotient; // decimal is assigned quotient for next operation
        counter  ; //counter is incremented so we can printf correct lentgh of array
        temp[i] = remainder; // sets our array at i = remainder
        i = i   1; //to increment i for every decimal > 0
    }
}

int main ()
{
    int counter = 0;
    int decimal;
    int base;

    //enterNumbers(decimal, base); // doesnt work yet

    printf("enter decimal:");
    scanf("%d", &decimal);
    printf("enter base:");
    scanf("%d", &base);
    // gets input decimal and base
    int *temp = calloc(decimal, sizeof(int));
    // alloc memory for array, worst case base = 1
    printf("decimal:%d, base:%d", decimal, base);
    // for test

    convert(decimal, base, counter, temp);
    // converts decimal into base number and sorts into array

    for (int i = 0; i < counter; i  )
    {
        printf(" %d,", temp[i]);
    }
    //should printf the array, which is the base number

    return 0;
}

well as stated above

CodePudding user response:

The main problem is that in C all function parameters are passed by value, which means that the value is copied into the parameter (which actually is just some special kind of local variable).

The result of is that the function modifies its own copy of while the original variable within main remains unchanged, thus your for loop printing the array runs from 0 up to (not including) 0, i.e. is not entered at all.

If you want to be able to modify a variable you pass to function you only can do so by passing the address of the variable to the function, which in C is done via a pointer:

void convert(int decimal, int base, int* counter, int temp[])
//                                     ^ (!)
{
    // code as is, but use *counter instead of counter now
}

Note that actually the same applies for the temp array, with function parameters (not everywhere else!) int temp[] is exactly equivalent to int* temp, so you again are just passing a pointer to the array.

Note, too, that i and *counter will after every loop run hold the same value, after loop completion both will hold the total number of digits contained. So you don't need to increment the counter with every loop run, but instead can assign i to it after the loop completed.

You'd now need to pass the address of the counter integer to the function:

convert(decimal, base, &counter, temp);
//                     ^ (!)

There's yet a better alternative, though: Functions can have return values, and instead of writing to a variable passed to which doesn't actually transport any information into the function you can use the return value to transport this information back.

As mentioned i holds the value of interest already. So just return it:

size_t convert(int decimal, int base, temp)
{
    size_t i = 0;
    // rest as you have, dropping any references to counter
    return i;
}

Note that I changed the counter type to size_t (you need to #include<stddef.h> for) – it is the semantically correct type for indicating memory sizes and so on. It's an unsigned type large enough to hold the size of any allocatable type on your system. If you don't like you can return an unsigned int as well (even int, but I'd prefer an unsigned value to indicate that negative values are meaningless anyway).

Finally: You missed a special case! If decimal is zero already you won't print out anything. You should catch this case separately and fill a single null value into the array returning 1 immediately.

Apart from the issues with convert function you have a memory leak for not freeing temp again after having used it (lacks free(temp)) and you might want to check the return values of calloc and scanf to catch failed memory allocation and invalid user input. Be aware, though, that scanf will scan for a string containing some digits followed by some non-digits (like 1210dal) only scan the numerical parts and ignore the non-digits (leading to failure of next digits to read) so checking the return value only is not safe in the general case (you might read an entire string or a complete line with fgets instead and parse this one, checking if all characters of have been consumed).

CodePudding user response:

In main() you initialize the variable to counter = 0 and do not change it after that. This means the for() where you print the result doesn't run. Arguments are passed by value in c, this means the value is copied, if you want to have an effect in the caller you can either return a value, or you can pass in a pointer to the variable (you can also use a global variable but we don't speak about in polite company). Here's passing in a pointer:

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

void convert(int decimal, int base, int *counter, int temp[])
{
    int remainder;
    int quotient;
    int i = 0;
    while (decimal > 0)
    {
        remainder = decimal % base; // remainder is stored
        quotient = (decimal - remainder) / base; //quotient is stored
        decimal = quotient; // decimal is assigned quotient for next operation
        (*counter)  ; //counter is incremented so we can printf correct lentgh of array
        temp[i] = remainder; // sets our array at i = remainder
        i = i   1; //to increment i for every decimal > 0
    }
}

int main ()
{
    int counter = 0;
    int decimal;
    int base;

    //enterNumbers(decimal, base); // doesnt work yet

    printf("enter decimal:");
    if(scanf("%d", &decimal) != 1) {
        printf("scanf failed\n");
        return 1;
    }
    printf("enter base:");
    if(scanf("%d", &base) != 1) {
        printf("scanf failed\n");
        return 1;
    }
    // gets input decimal and base
    int *temp = calloc(decimal, sizeof(int));
    if(!temp) {
        printf("calloc failed\n");
        return 1;
    }
    // alloc memory for array, worst case base = 1
    printf("decimal:%d, base:%d", decimal, base);
    // for test

    convert(decimal, base, &counter, temp);
    // converts decimal into base number and sorts into array

    for (int i = 0; i < counter; i  )
    {
        printf(" %d,", temp[i]);
    }
    //should printf the array, which is the base number
    free(temp);
}

and example run (observe that the result is reversed of the usual notation):

enter decimal:10
enter base:2
decimal:10, base:2 0, 1, 0, 1,

Here's a more heavily revised version that returns the count, uses a smaller data type than 'int' for each digit, and uses log2() to determine how many digits you need (you will need to link with -lm for that). Tweaked the prompts a bit too. Reversed the result on output.

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

int convert(unsigned decimal, unsigned base, unsigned char temp[]) {
    int i = 0;
    for(; decimal > 0; i  ) {
        temp[i] = decimal % base;
        decimal = (decimal - temp[i]) / base;
    }
    return i;
}

int main(void) {
    printf("enter decimal: ");
    unsigned decimal;
    if(scanf("%u", &decimal) != 1) {
        printf("scanf failed\n");
        return 1;
    }

    printf("enter base: ");
    unsigned base;
    if(scanf("%u", &base) != 1) {
        printf("scanf failed\n");
        return 1;
    }
    if(base < 2 || base > 10) {
        printf("base must be between 2 and 10\n");
        return 1;
    }

    int len = log2(decimal) / log2(base)   1;
    unsigned char *temp = calloc(len   1, sizeof(unsigned char));
    if(!temp) {
        printf("calloc failed\n");
        return 1;
    }
    int counter = convert(decimal, base, temp);
    for (int i = counter; i; i--)
    {
        printf("%d%s", temp[i-1], i - 1 ? ", " : "\n");
    }
    free(temp);
}

and example run:

enter decimal: 10
enter base: 2
1, 0, 1, 0

Instead of dynamically allocate temp you can use worse case, i.e. log2(INT_MAX) which is sizeof(int) * CHAR_BIT:

unsigned temp[sizeof(int) * CHAR_BIT   1];
  •  Tags:  
  • c
  • Related