5

I have a messy block of code like

result = (node*)malloc(sizeof(node));
result->fx = (char*)malloc(sizeof(char) * 2);
result->fx[0]='x'; result->fx[1]='\0';
result->gx = NULL; result->op = NULL; result->hx = NULL;

where I initialize an element of type

typedef struct node
{
    char * fx; // function
    struct node * gx; // left-hand side
    char * op; // operator
    struct node * hx; // right-hand side
} node;

Is there a shorthand way of doing that? In other words, is there a way to do like I would do in C++?

result = new node { new char [] {'x','\0'}, NULL, NULL, NULL };
Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • 1
    Unfortunately no. If you want to initialize all fields with 0, you can use `calloc`. And don't typecast the result of `malloc`. – Mohit Jain May 26 '15 at 05:18
  • 1
    If `fx` is always going to be malloc'd with the same size then you could make it an array – M.M May 26 '15 at 05:31
  • 1
    Can you clarify whether `'x'` is to be hardcoded, or if this is pseudocode and you want to initialize `fx` with data that's been entered by the user for example? – M.M May 26 '15 at 05:52

2 Answers2

7

You can write your own wrapper function:

static node *getNewNode(char *fx) {
  node *p = calloc(1, sizeof *p);
  if(p && fx) {
    p->fx = malloc(strlen(fx) + 1);
    if(!p->fx) {
      free(p);
      p = null;
    } else {
      strcpy(p->fx, fx);
    }
  }
  return p;
}

Later you can call this as:

node *result = getNewNode("x");
if(result) ...

Which is more readable and less cluttery.

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
5

You can't have two nested mallocs and initialize everything in one go. However I would suggest the following design:

typedef struct node
{
    char fx[2], op[2];    // first byte being null indicates not-present
    struct node *gx, *hx;
} node;

and then you can more simply write:

node *result = malloc( sizeof *result );

if ( !result )
    errorhandling......

// C89
node temp = { "x" };
*result = temp;

// C99
*result = (node){ .fx = "x" };

The C99 example uses compound literals and designated initializers which are in C but not C++. For more discussion see How to initialize a struct in ANSI C.

You don't have to use the designated initializer but it reduces the possibility for error. Any struct members not explicitly initialized will be initialized as if by 0.

In both cases, the theoretical temporary object will be optimized away, so this solution should not be considered inefficient at all.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • It might be worth mentioning that `"x"` is a string literal and therefore the final value of `result->fx` pointing to will not be modifiable. This is a limitation to the OP's approach. – alk May 26 '15 at 06:07
  • 1
    This means you'll create an extra temporary object on the stack though. A better solution would perhaps be to create a `static const node` with everything already in place. – Lundin May 26 '15 at 07:04
  • @Lundin I compiled with `-O1` and there is no temporary object created on the stack. The assembly instruction `movq` is used to place `'x'` directly in the malloc'd space. Can you show the code for your suggestion? (bearing in mind that OP probably intends `"x"` to be a value obtained at runtime) – M.M May 26 '15 at 07:54
  • @alk `fx` is a modifiable array which the string literal is copied into. The final result is modifiable. – M.M May 26 '15 at 07:56
  • If `"x"` is a run-time input then `static` wouldn't be possible and then it doesn't make sense to have such a `const` object. Otherwise, using the type definition in your example: `static const node DEFAULT = { "x", {'\0'}, NULL, NULL }; ... *result = DEFAULT;` Use designated initializers or don't, it doesn't matter. – Lundin May 26 '15 at 08:27
  • Ah I see, you changed the `struct`'s defintion. – alk May 26 '15 at 08:32
  • @MattMcNabb So does this version if you remove `static`. Anyway, the theoretical temporary object on the stack might very well get optimized away anyhow. – Lundin May 26 '15 at 11:50