3

I'm dynamically allocating an array in main() to store the prime factors of any number calculated through a PrimeFactors() function I coded myself. Problem is, when the size of the array >= 4, the program displays what looks like undefined behavior; reading garbage values and whatnot. Works perfectly when size < 4.

I thought that maybe the array address was changing through the function and as a consequence main() would read garbage values, not knowing the "new" address of the array; and it seems like this is the case.

OS is Linux Ubuntu 18.04 LTS.

As i am learning I do not want to simply use vector and forget about this problem.

Why is this happening and what could I do to fix this ? I am clueless and it seems google and SO are as well.

Here's the main() code :

int main(int argc, char* argv[])
{
    unsigned long long n = atoll(argv[1]);

    unsigned long long* factors = malloc(sizeof(unsigned long long));
    if(factors == NULL)
    {
        printf("malloc failed to allocate factors\n");
        return -1;
    }
    else
        printf("First address in main() %p\n\n", (void *)&(factors[0]));

    unsigned short int* size = malloc(sizeof(unsigned short int));
    if(size == NULL)
    {
        printf("malloc failed to allocate size\n");
        return -1;
    }

    PrimeFactors(factors, size, n);

    printf("Last address in main() : %p\n", (void *)&(factors[0]));

    for(int i = 0; i < *size; ++i)
        printf("%llu\n", factors[i]);

    free(factors);
    free(size);
    return 0;
}

And here's the PrimeFactors() code :

int PrimeFactors (unsigned long long* factors, unsigned short int* size, unsigned long long n)
{
    printf("In PrimeFactors() :\n");
    *size = 2;
    factors = realloc(factors, (*size) * sizeof(unsigned long long));
    if (factors == NULL)
    {
        printf("realloc failed re-allocating factors array\n");
        return -1;
    }
    else
        printf("realloc() %d address in PrimeFactors() : %p\n", *size, (void *)&(factors[0]));

    if (IsPrime(n))
    {
        factors[0] = n;
        return 0;
    }

    unsigned short int factorsCount = 0;
    for (unsigned long long i = 2; i <= n; ++i)
    {
        while(n % i == 0)
        {
            if(factorsCount >= *size)
            {
                factors = realloc(factors, ++(*size) * sizeof(unsigned long long));
                if (factors == NULL)
                {
                    printf("realloc failed re-allocating factors array\n");
                    return -1;
                }
                else
                    printf("realloc() %d address : %p\n", *size, (void *)&(factors[0]));
            }
            factors[factorsCount] = i;
            ++factorsCount;

            n /= i;
        }
    }

    printf("last address in PrimeFactors() : %p\n", (void *)&(factors[0]));
    for(int i = 0; i < *size; ++i)
        printf("%llu\n", factors[i]);

    printf("Exiting PrimeFactors()...\n\n");
    return 0;
}

Compile flags :

gcc -Wall -Wshadow -Wpointer-arith main.c libMath.c -o learnlab.exe

Execute command :

./learnlab 80

Expected output :

First address in main() 0x5626aa180260

In PrimeFactors() :

realloc() 2 address in PrimeFactors() : 0x5626aa180260

realloc() 3 address : 0x5626aa180260

realloc() 4 address : 0x5626aa180260

realloc() 5 address : 0x5626aa180260

last address in PrimeFactors() : 0x5626aa180260

2

2

2

2

5

Exiting PrimeFactors()...

Last address in main() : 0x5626aa180260

2

2

2

2

5

Actual output :

First address in main() 0x5626aa180260

In PrimeFactors() :

realloc() 2 address in PrimeFactors() : 0x5626aa180260

realloc() 3 address : 0x5626aa180260

realloc() 4 address : 0x5626aa1812b0

realloc() 5 address : 0x5626aa1812b0

last address in PrimeFactors() : 0x5626aa1812b0

2

2

2

2

5

Exiting PrimeFactors()...

Last address in main() : 0x5626aa180260

0

2

2

4113

7233098161058900294

Sorry this is a long post, I couldn't really figure out a way to make it shorter. Thank you.

13
  • 1
    Just for your information, but e.g. factors and &factors[0] is exactly the same. Commented May 31, 2018 at 7:13
  • 1
    Well, you are in luck. Since this is C -- you don't have the option of using vector (unless you write it yourself) :) (and very well done on your question) Commented May 31, 2018 at 7:13
  • 5
    As for your problem, remember that C only have pass-by-value. When you pass an argument to a function, it is copied. Any assignments you make to the local argument variable only modifies the copy, not the original. Please do some research about emulating pass by reference in C (which you already do with the size argument). Commented May 31, 2018 at 7:15
  • 4
    Basically you must call unsigned long long **factors, ... to be able to realloc in your function. Otherwise, the new address for factors is never seen in main() because your function receives a copy of the pointer. So you are required to pass its address, if you want to change that with realloc within the function and have the change seen in main() (right now you have a nice memory leak) Commented May 31, 2018 at 7:18
  • 1
    Oh and you don't need malloc to create pointers. Using e.g. unsigned short size = 1; and then use the address-of operator as in &size is enough (and what is usually done). Commented May 31, 2018 at 7:24

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.