0
    struct Heap {
        int capacity;
        int heapSize;
        int *tree;     // the heap binary tree
        int *pos;       // pos[i] is the position of values[i] in items
        float *p;  // priority value of each heap element
    };

    void initHeap(struct Heap *heap, int capacity) {
        heap->capacity = capacity;
        heap->heapSize = 0;
        heap->tree = malloc(sizeof(int)*(capacity+1));
        heap->pos = malloc(sizeof(int)*(capacity+1));
        heap->p = malloc(sizeof(float)*(capacity+1));
    }

    void betterInit(struct Heap *heap, int capacity) {
        with (heap) { // doesn't exist
            capacity = capacity;
            heapSize = 0;
            tree = malloc(sizeof(int)*(capacity+1));
            pos = malloc(sizeof(int)*(capacity+1));
            p = malloc(sizeof(float)*(capacity+1));
        }
    }
// update heap after a value is increased
void upHeap(struct Heap *heap, int i) {
    int *tree = heap->tree, *pos = heap->pos;
    float *p = heap->p;
    int c, r;

    c = pos[i];         // position of element i-th in heap
    while (true) {
        r = parent(c);
        if (r==0 || p[tree[r]] >= p[i]) break; // if c is root, or priority(parent(c)) is > priority(c)
        pos[tree[r]] = c;  // pull the parent down to c
        tree[c] = tree[r];
        c = r;
    }
    tree[c] = i;
    pos[i] = c;
}

So the 1st initHeap looks long because I have to write heap-> a lot of times. And I wish to make it look shorter.

One solution is to write:

int *tree = heap->tree;
int *pos = heap->pos;
float *p = heap->p;

and then use tree, pos, p. Are there more ways?

Huy Le
  • 1,439
  • 4
  • 19
  • 2
    Sorry, C doesn't have any shortcuts for this. – Barmar Mar 12 '20 at 03:32
  • 2
    Your current `initHeap` looks perfectly fine, readable, and idiomatic to me. – Nate Eldredge Mar 12 '20 at 03:33
  • Oh that's sad :( @NateEldredge it looks good until something like heap->tree[heap->pos[i]] – Huy Le Mar 12 '20 at 03:47
  • If you want Pascal, you can use it. A `with` clause is confusing, though, even in Pascal. – Jonathan Leffler Mar 12 '20 at 03:58
  • Related: https://stackoverflow.com/questions/2279180/does-c-have-with-keyword-like-pascal – Jerry Jeremiah Mar 12 '20 at 04:01
  • You could rename the variable. `void betterInit(struct Heap *h, ...` – William Pursell Mar 12 '20 at 04:01
  • 1
    Note that the line `capacity = capacity;` indicates just one of the problems that would arise if the `with` clause were available — is that a shorthand for `heap->capacity = capacity;` or `capacity = heap->capacity;` or `heap->capacity = heap->capacity;` or `capacity = capacity;`? The answer is that a compiler couldn't tell — the code would have to be changed, perhaps so that the argument was `cap` instead of `capacity`. It gets messy very quickly! – Jonathan Leffler Mar 12 '20 at 04:02
  • This answer is for C# but the same reasons apply to other languages: https://stackoverflow.com/a/601163/2193968 – Jerry Jeremiah Mar 12 '20 at 04:02

3 Answers3

7

You can initialise a struct using C99's designated initialiser syntax:

void initHeap(struct Heap *heap, int capacity) {
    *heap = (struct Heap){
        .capacity = capacity,
        .heapSize = 0,
        .tree = malloc(sizeof(int)*(capacity+1)),
        .pos = malloc(sizeof(int)*(capacity+1)),
        .p = malloc(sizeof(float)*(capacity+1))
    };
}
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
rici
  • 234,347
  • 28
  • 237
  • 341
  • This is probably closest to what OP is looking for. But I think it's less idiomatic. It also means that the entire struct will be initialized (with zeros for the members you don't mention), which may waste CPU cycles if there were members that didn't need initializing. – Nate Eldredge Mar 12 '20 at 04:03
  • 1
    @nate: it's certainly part of my idiom :-). It's true that there is a cohort of programmers who are reluctant to use "new" features (i.e. only 20 years old), but there are many others who do. Yes, it does initialise the entire object, so you can't use it for partial updates. Personally I think it's good to initialise entire structures; it costs little and it's a lot safer. In the case of a member which is just about to be set to a different value, the compiler may be able to optimise anyway. But obviously everyone must use their own judgement. – rici Mar 12 '20 at 04:10
  • Can this be done with functions other than the initializer ? I added another function in the question. – Huy Le Mar 12 '20 at 04:11
  • @huy: you can use it as you see fit. Just remember that an entire object is constructed; you can't use it to just update a couple of members. As Nate says, you don't have to mention every member (although I often do) because the ones you don't explicitly name will be zero-initialised. – rici Mar 12 '20 at 04:17
1

What about good old macros?

struct Heap {
    int capacity;
    int heapSize;
    int *tree;     // the heap binary tree
    int *pos;       // pos[i] is the position of values[i] in items
    float *p;  // priority value of each heap element
};

#define _(x) heap->x
void initHeap(struct Heap *heap, int capacity) {
    _(capacity) = capacity;
    _(heapSize) = 0;
    _(tree) = malloc(sizeof(int)*(capacity+1));
    _(pos) = malloc(sizeof(int)*(capacity+1));
    _(p) = malloc(sizeof(float)*(capacity+1));
}
/* More struct Heap related functions */
#undef _

If used in a disciplined way and for having terse code in the implementation of this library, I don't find it such a bad idea. And, as a bonus, it works also for partial updates and when imported in C++ compilers (I know this doesn't look very significant).

As a side comment, why the capacity+1 in the calls to malloc()?

Costantino Grana
  • 3,132
  • 1
  • 15
  • 35
  • Huh that's actually it :D the above comment only works as for initializer. Also, capacity+1 because my implementation stores in 1->n, with tree[0] as a special element – Huy Le Mar 12 '20 at 12:36
-3

How about using a dot "." ? Like

struct Heap {
    int capacity;
    int heapSize;
    int *tree;     // the heap binary tree
    int *pos;       // pos[i] is the position of values[i] in items
    float *p;  // priority value of each heap element
}H; //to make abbreviation for Heap

then use

H.capacity = capacity;
H.heapsize = 0;
  • 4
    That only works if you have a struct, not a pointer to struct. `.` and `->` are not interchangeable. In an initializer method, you'll always have a pointer; you can't initialize the caller's struct if they pass it by value after all. `H` isn't making an abbreviation for `Heap` there, it's declaring a single instance of the struct named `H`, which is not the same thing. – ShadowRanger Mar 12 '20 at 03:38