2
typedef struct {
    char a[100];
    char const *secondHalfOfA;
}
//Can i set { secondHalfOfA = a[49]; } somehow?

4 Answers 4

3

Sure you can.

typedef struct {
    char a[100];
    char const *const secondHalfOfA;
} toto;
#define TOTO_INITIALIZER(NAME) { .secondHalfOfA = &((NAME).a[49]) }

static toto A = TOTO_INITIALIZER(A);

Using initializers like that consistently has the extra plus that it initializes your array with all 0, too.

This is for C99 with designated initializers. If you only have historical C you could do something like

#define TOTO_INITIALIZER(NAME) { { 0 }, &((NAME).a[49]) }

Edit: Seeing your comment on another answer, I suppose that you had the const in your type on the wrong side. But real C initialization works very well for that case, too.

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

Comments

2

You cannot automatically initialize a pointer to the middle of an object.

You can, however, pretend to have overlapping objects. It's not pretty though :-)

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

struct twoparts {
  union {
    char a[20];
    struct {
      char dummy[10];
      char b[10];
    } s;
  } u;
};

int main(void) {
  struct twoparts x;
  strcpy(x.u.a, "1234567890123456789");
  printf("second part: %s\n", x.u.s.b);
  return 0;
}

2 Comments

"It's not pretty though" StackOverflow needs an understatement badge. I think that one statement would get you a gold one. ;-)
You're probably better off with #define secondHalfOfA(s) ((s).a + 49), then use secondHalfOfA(A) instead of A.secondHalfOfA.
1

No. You can't do that in a typedef. Remember: with typedef keyword you are defining data types, not variables.

In C++ you can do that in the default constructor. But in C, there is no way to do that.

Comments

1

Is Pablo said, you can't do that with an initializer. You can do it easily enough after initialization, but it has to be every time:

// Definition (once)
typedef struct {
    char a[100];
    char const *secondHalfOfA;
} TYPENAME;

// Use (each time)
TYPENAME t;
t.secondHalfOfA = &t.a[49];

// Or
TYPENAME *pt;
pt = malloc(sizeof(*pt));
pt->secondHalfOfA = &pt->a[49];

It's for reasons like this that we have object oriented languages like C++ (and Java and ...) and their associated constructors, so that we can create structures with custom initializations reliably.


Demonstration program:

#include <stdio.h>

// Definition (once)
typedef struct {
    char a[100];
    char const *secondHalfOfA;
} TYPENAME;

int main(int argc, char* argv[])
{
    // Use of the type (need to initialize it each time)
    TYPENAME t;
    t.secondHalfOfA = &t.a[49];

    // Example actual use of the array
    t.a[49] = 'A';
    printf("%c\n", *t.secondHalfOfA); // Prints A

    // Uncommenting the below causes a compiler error:
    // "error: assignment of read-only location ‘*t.secondHalfOfA’"
    // (That's gcc's wording; your compiler will say something similar)
    //*t.secondHalfOfA = 'B';
    //printf("%c\n", *t.secondHalfOfA);

    return 0;
}

Compilation and output using gcc:

$ gcc -Wall temp.c
$ ./a.out
A

3 Comments

I didn't think i would be able to do this: t.secondHalfOfA = &t.a[49]; as it is a constant. I thought it could not be assigned to. Thanks
@tm1rbrt: No, char const * is a pointer to static data, not a static pointer. The above is fine, as long as you don't try to write a character via the secondHalfOfA pointer. I've added a sample program showing the difference.
@tm1rbrt: If you wanted to make the pointer constant (which would make the above stop working), it would be char * const (I had to remind myself). More here: stackoverflow.com/questions/1658977/…

Your Answer

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