3

I want to be able to reference variable sized array with a global pointer. But what kind of pointer do I use that will work with variable sizes of the array? In the example below, assume N will only be known at runtime (could be an argument for example) so compile time solutions won't work.

What I want to achieve:

main.c

some_sort_of_pointer *x;

main()
{
    int N=256; //or N=64 or whatever
    char (*LC)[N];

    LC=malloc(1024);
    x=LC;
    memcpy(x[2],"hello world",11);
    x[0][176]=123;

    dostuff();
}

I'm sure there's an easy obvious way to do this but I can't seem to nail it. My first attempt at asking this was a mess so this time I'm hoping it's clear what I want to achieve.

OS Centos 6.5

compiler GCC 4.8 (using C99)

3
  • The only type that you can declare globally and assign to the address of a VLA is void *. If your pointer wasn't at global scope, then you could use a proper pointer-to-(variable length) array. Commented Aug 3, 2014 at 7:29
  • @BLUEPIXY yeah, I didn't say it could, I was just making a factual observation. Commented Aug 3, 2014 at 8:01
  • Any VLA or other type which references a VLA (e.g. a pointer to one) can only occur inside a function (or the function's parameter list). You can't have a global pointer to VLA. To achieve such an effect your only option is going to be to write some code to store array sizes and calculate offsets. Commented Aug 3, 2014 at 10:24

2 Answers 2

2

As at compile time the type to be referenced isn't given, a void pointer might help.

However only storing an untyped reference (what void * in fact is is) is not enough, as it is essential to also know the size of the (VL)array. So the latter also needs to be stored globally, as it can not be pulled from the memory referenced.

An example how this can be achieve is given below:

main.h:

#include <stdlib.h> /* for size_t */

struct VLA_descriptor
{
  void * p;
  size_t s;
} 

extern struct VLA_descriptor vla_descriptor;

foo.h:

void foo(void);

foo.c:

#include "main.h"
#include "foo.h

void foo(void)
{
  char (*p)[vla_descriptor.s] = vla_descriptor.p;

  /* Do something with the VLA reference p. */
}

main.c:

#include "main.h"
#include "foo.h"

struct VLA_descriptor vla_descriptor = {0};

int main(int argc, char ** argv)
{
  size_t s = atoi(argv[1]);
  char (*p)[s] = malloc(s);

  vla_descriptor.p = p;
  vla_descriptor.s = s;

  foo();

  ... /* Free stuff and return. */
}

Error checking had been omitted in this example's code for the sake of readability.

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

1 Comment

It's a novel solution! I am hoping (probably in vain) to get an answer that results in a single simple global pointer, but in the absence of such, this one will get the gong. I am disappointed and somewhat surprised that what I'm looking for may not be possible.
0

With much thanks to @alk (and everyone else who responded) I think I have the closest I'm going to get to what I'm looking for:

void *LC
int LCS;
int main(int argc, char **argv) {
    LCS=256;
    LC=malloc(1024)
    memcpy(((char(*)[LCS])LC)[2],"hello world",11);
    ((char(*)[LCS])LC)[0][176]=123;
    printf("%d %s\n",((char(*)[LCS])LC)[0][176],&((char(*)[LCS])LC)[2]);
}

((char(*)[LCS])LC) is the equivalent of a what I wanted. It's similar to @alk's idea and does require 2 globals but it means I can use it in functions without having to declare a new variable. I've credited @alk with the answer as what he posted gave me 90% of what I needed.

Though if anyone can reduce ((char(*)[LCS])LC) to a single global, I would be excited to see it :)

2 Comments

((char *)LC + 2 * LCS) seems more readable to me, YMMV I suppose :) You could wrap this up in an inline function or macro , e.g. ELEMENT_OF(LC, 2) instead of ((fuglycast)LC)[2]
Define #define CASTIT(LC, LCD) ((char(*)[(LCS)])(LC)) and use CASTIT(LCD, LC) instead of ((char(*)[LCS])LC). Matt's approach covers even more.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.