2

I'm trying to create a function that concatenates 2 arrays and then returns the sum array back. I've been using the following code:

    #include "stdio.h";

struct array {
    int length;
    int *array;
};

struct array add(struct array a, struct array b) {
    int length = a.length + b.length;
    int sum[length];
    for (int i = 0; i < length; ++i) {
        if (i < a.length) {
            sum[i] = a.array[i];
        } else {
            sum[i] = b.array[i - a.length];
        }
    }

    struct array c;
    c.length = length;
    c.array = sum;
    return c;
}

int main() {
    int a[] = {1, 2, 3};
    struct array s1;
    s1.array = a;
    s1.length = sizeof(a) / sizeof(a[0]);

    int b[] = {4, 5, 6};
    struct array s2;
    s2.array = b;
    s2.length = sizeof(b) / sizeof(b[0]);

    struct array sum = add(s1, s2);
    for (int i = 0; i < sum.length; ++i) {
        printf("%d\n", sum.array[i]);
    }
    return 0;
}

The output is: 1, 17, 6356568, 1959414740, 1, 1959661600

What am I doing wrong?

ad absurdum
  • 19,498
  • 5
  • 37
  • 60
user2997204
  • 1,344
  • 2
  • 12
  • 24

5 Answers5

4

These three lines are very problematic:

int sum[length];
...
c.array = sum;
return c;

In the first you declare the local variable sum. In the second you make c.array point to the local variable. And in the third line you return the pointer while the local variable goes out of scope.

Since the local variable goes out of scope it no longer exists, and the pointer to it is no longer valid. Using the pointer will lead to undefined behavior.

To solve this you need to allocate memory dynamically with e.g. malloc.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

sum is a local variable to the add function. When you set c.array = sum;, then the pointer c.array points to this local variable.

After the function returns, local variables are destroyed. So this pointer is now a dangling pointer. But in main you then read through this pointer.

To fix this you'll need to make a fundamental change to the design of your program. For example, use dynamic allocation in all cases for a struct array.

M.M
  • 138,810
  • 21
  • 208
  • 365
1

Arrays in C simply are a contiguous area of memory, with a pointer to their start*. So merging them involves:

  1. Find the length of the arrays A and B, (you will probably need to know the number of elements and the sizeof each element)
  2. Allocating (malloc) a new array C that is the size of A + B.
  3. Copy (memcpy) the memory from A to C,
  4. Copy the memory from B to C + the length of A (see 1).

You might want also to de-allocate (free) the memory of A and B.

Example code snippet:

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

#define ARRAY_CONCAT(TYPE, A, An, B, Bn) \
(TYPE *)array_concat((const void *)(A), (An), (const void *)(B), (Bn), sizeof(TYPE));

void *array_concat(const void *a, size_t an,const void *b, size_t bn, size_t s)
{
    char *p = malloc(s * (an + bn));
    memcpy(p, a, an*s);
    memcpy(p + an*s, b, bn*s);
    return p;
}

// testing
const int a[] = { 1, 1, 1, 1 };
const int b[] = { 2, 2, 2, 2 };

int main(void)
{
    unsigned int i;

    int *total = ARRAY_CONCAT(int, a, 4, b, 4);

    for(i = 0; i < 8; i++)
        printf("%d\n", total[i]);

    free(total);
    return EXIT_SUCCCESS;
}
Prakhar Agarwal
  • 2,724
  • 28
  • 31
0

Try this - corrected add function:

#include <stdlib.h>

struct array add(struct array a, struct array b) {
    int length = a.length + b.length;
    int * sum = (int*)calloc(length, sizeof(int));
    for (int i = 0; i < length; ++i) {
        if (i < a.length) {
            sum[i] = a.array[i];
        }
        else {
            sum[i] = b.array[i - a.length];
        }
    }

    struct array c;
    c.length = length;
    c.array = sum;
    return c;
}

stdlib is required to use calloc function.

That function allocate memory for length values of int type. To be sure that memory is allocated successfully, it is recommended to check value of pointer sum after allocation, e.g.:

 int * sum = (int*)calloc(length, sizeof(int));
 if( sum != NULL )
 {
     // use memory and return result
 }
 else
 {
     // do not use pointer (report about error and stop operation)
 }
VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • Why `calloc`? You overwrite every element in the loop so `malloc`should do, I guess. No need for a cast, btw. Of topic: I would prefer two for-loops and avoid the if-statement. – Support Ukraine Oct 18 '16 at 05:22
  • 1
    You're about to write to every allocated byte; there's no need to use `calloc()` which also writes to every allocated byte. – Jonathan Leffler Oct 18 '16 at 05:22
  • 1
    @4386427: Beat me by 2 seconds...if I hadn't gotten distracted... – Jonathan Leffler Oct 18 '16 at 05:23
  • No problem, `malloc` can be used instead of `calloc`, and cast can be removed, and of course two `for` - everybody can write as he/she like, I have just made minimal changes to make code able to work – VolAnd Oct 18 '16 at 05:31
0

As Joachim mentioned, you are returning a local variable int sum[length]; This is a bad idea. The variable sum is returned to the stack after the function exits and can be overwritten by other stack variables.

One of the ways around that is to not declare an array inside the sum function in the first place. The sum_str is declared in main. You can pass the pointer to this structure to the sum function.

The updated code is below.

#include <stdio.h>

struct array {
    int length;
    int *array;
};

void add(struct array a, struct array b, struct array *sum_str) {
    sum_str->length = a.length + b.length;
    for (int i = 0; i < sum_str->length; ++i) {
        if (i < a.length) {
            sum_str->array[i] = a.array[i];
        } else {
            sum_str->array[i] = b.array[i - a.length];
        }
    }
}

int main() {
    int a[] = {1, 2, 3};
    struct array s1;
    s1.array = a;
    s1.length = sizeof(a) / sizeof(a[0]);

    int b[] = {4, 5, 6};
    struct array s2;
    s2.array = b;
    s2.length = sizeof(b) / sizeof(b[0]);

    struct array sum_str;
    int sum_a[6];
    sum_str.array = sum_a;

    add(s1, s2, &sum_str);
    for (int i = 0; i < sum_str.length; ++i) {
        printf("%d\n", sum_str.array[i]);
    }
    return 0;
}

Another way is to use dynamic memory allocation as described by other answers.

Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31