1

I am trying to create a array of structure elements and reallocate if I need new elements. The array has to be a pointer because I want to return it from the function.

I have the following code:

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

  struct rle_element {
    int length;
    char character;
  };

  void get_rle() {
    struct rle_element *rle = malloc(sizeof(struct rle_element*));
    struct rle_element **rle_pointer = &rle;

    rle = realloc(rle, sizeof(rle) + sizeof(struct rle_element*));

    (*rle_pointer)->length = 10;
    printf("%d\n", (*rle_pointer)->length);

    rle_pointer = &rle+1;

    (*rle_pointer)->length = 20;
    printf("%d\n", (*rle_pointer)->length);

  }

  int main() {
      get_rle();

      return EXIT_SUCCESS;
  }

But this code isn't really working. I think the reallocate is not right.

Now I have the following code which works fine. But I can also use rle[2] or rle[3] without allocate. I think my programm only allocate space for two items.

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

  struct rle_element {
    int length;
    char character;
  };

  void get_rle() {
    struct rle_element *rle = malloc(sizeof(struct rle_element));
    struct rle_element **rle_pointer = &rle;

    rle = realloc(rle, sizeof(rle) + sizeof(struct rle_element));

    rle[0].length = 10;
    printf("%d\n", rle[0].length);

    rle[1].length = 20;
    printf("%d\n", rle[1].length);
  }

  int main() {
      get_rle();

      return EXIT_SUCCESS;
  }
5
  • 1
    You forgot to ask a question. Commented Jan 23, 2019 at 20:28
  • What do you mean by isn't working? What is it supposed to do and what actually happens? Commented Jan 23, 2019 at 20:37
  • 1
    When I run the above code it prints 10 in the first line and "Segmentation fault".in the second line Commented Jan 23, 2019 at 20:41
  • sizeof(struct rle_element*) is the size of a pointer (probably either 4 or 8 bytes depending on your hardware). You want sizeof(struct rle_element). Commented Jan 23, 2019 at 20:50
  • I tried this but I get the same error message. Commented Jan 23, 2019 at 20:57

3 Answers 3

1

There are various problems with your code (pointed out in comments and other answers). One critical thing that you are missing is that you are not tracking the size of the allocated region. sizeof() is evaluated at compile-time (unless you are using C99 VLAs). So doing sizeof(rle) is not going to evaluate to the number of bytes that your array is using. You have to store that separately. Here is a working implementation that tracks the size with a struct rle_parent structure with comments included to help you understand:

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

struct rle_element {
    int length;
    char character;
};

struct rle_parent {
    struct rle_element *arr;
    size_t count;
};

static void get_rle(struct rle_parent *p, int length, char character) {
    struct rle_element *e;

    /* Allocate enough space for the current number of elements plus 1 */
    e = realloc(p->arr, (p->count + 1) * sizeof(struct rle_element));
    if (!e) {
        /* TODO: (Re)allocation failed, we should handle this */
        return;
    }

    /* Update the parent to point to the reallocated array */
    p->arr = e;

    /* Update our newly added element */
    e = &p->arr[p->count];
    e->length = length;
    e->character = character;

    /* Bump the count so we know how many we have */
    p->count++;
}

int main() {
    struct rle_parent p;
    size_t i;

    /* Initialize */
    p.arr = NULL;
    p.count = 0;

    get_rle(&p, 10, 'a');
    get_rle(&p, 20, 'b');
    get_rle(&p, 30, 'c');

    /* Print out our array */
    for (i = 0; i < p.count; i++) {
        struct rle_element *e = &p.arr[i];
        printf("%d -- %c\n", e->length, e->character);
    }

    return 0;
}

Alternatively, if you don't want to maintain a count, you could add another field to struct rle_element that indicates that it is the last element in the array. You would have to update that each time you add a new element (clearing it on the "current" last element and setting it on the "new" last element), but you could get rid of the struct rle_parent in that case.

Also, passing NULL as the first argument to realloc(), makes it behave like a call to malloc(), so it works out cleanly here.

Sign up to request clarification or add additional context in comments.

Comments

0

While it's already mentioned that you're allocating the space of a pointer and not the structure itself, there's another, issue.

rle_pointer = &rle+1;

Will not get you the address of a pointer to rle[1].

With the other change proposed, you'll still get a segfault, however if you also try

rle[1].length=20;
printf("%d\n", rle[1].length);

Instead of

(*rle_pointer)->length = 20;
printf("%d\n", (*rle_pointer)->length);

You'll have the code successfully work. This would indicate your realloc() has worked successfully.

To explain a bit better, a double pointer is actually a pointer to a pointer. There is no pointer at &rle+1. Your code is trying to dereference a pointer that doesn't exist.

Instead of

 rle_pointer = &rle+1;

You could just say

rle += 1;

If you insist upon doing it this way. Otherwise, I'd suggest sticking to using rle as an array and avoiding the double pointer.

For the update: it's writing and reading unallocated memory (causing UB) afaik.

You can validate this by freeing rle and trying to do the same behaviour, on gcc 7.4.0 I can do the same.

2 Comments

I am trying to use rle as an array.
You shouldn't need an rle_pointer then. I updated a bit at the end to explain the next problem, afaik it's reading and writing to unallocated memory causing UB that happens to work out.
0

malloc and realloc required the size of the space to reserve(allocate) in the memory, so if you want to make an array you must allocate the size of 1 element multiplied by the number of elements in the array, I suggest you make a variable to hold the size of the array. BTW "Segmentation fault" as far as I know, means you are using space that you did not allocate for.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.