Home > Blockchain >  How to refer to a specific struct in an array, while the array is in a struct in a function in C?
How to refer to a specific struct in an array, while the array is in a struct in a function in C?

Time:12-04

    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <math.h> // sqrtf
    #include <limits.h> // INT_MAX
    #include <string.h> // strcmp, strlen, strcat
    #include <time.h> // time.NULL


    int logger = 0;
    struct obj_t {
        int id;
        float x;
        float y;
    };
     
    struct cluster_t {
        int size;
        int capacity;
        struct obj_t *obj;
    };
     
    
    void point_ctor(struct obj_t *p,int id, float x, float y){
     
        p->id = id;
        p->x = x;
        p->y = y;
     
    }
     
    void init_cluster(struct cluster_t *c, int cap)
    {
        assert(c != NULL);
        assert(cap >= 0);
     
        // TODO
        c->capacity = cap;
        c->size = 0;
        c->obj = NULL;
     
    }
     
   
     
    /// Chunk of cluster objects. Value recommended for reallocation.
    const int CLUSTER_CHUNK = 10;
     
    
    struct cluster_t *resize_cluster(struct cluster_t *c, int new_cap)
    {
        // TUTO FUNKCI NEMENTE
        assert(c);
        assert(c->capacity >= 0);
        assert(new_cap >= 0);
     
        if (c->capacity >= new_cap)
            return c;
     
        size_t size = sizeof(struct obj_t) * new_cap;
     
        void *arr = realloc(c->obj, size);
        if (arr == NULL)
            return NULL;
     
        c->obj = (struct obj_t*)arr;
        c->capacity = new_cap;
        return c;
    }
     
    
    void append_cluster(struct cluster_t *c, struct obj_t obj)
    {
        // TODO
     
        if(c->size == c->capacity){
            resize_cluster(c,(c->capacity) 1);
        }
        c->size  = 1;
        //point musim pridat c->obj[(c->size)-1] strukt arg 2
        c->obj[((c->size)-1)].id = obj.id;
        printf("TUSOM");
        c->obj[(c->size)-1].x = obj.x;
        printf("TUSOM");
        c->obj[(c->size)-1].y = obj.y;
        printf("TUSOM");
     
    }
     
    

   
    void print_cluster(struct cluster_t *c)
    {
        // TUTO FUNKCI NEMENTE
        for (int i = 0; i < c->size; i  )
        {
            if (i) putchar(' ');
            printf("%d[%g,%g]", c->obj[i].id, c->obj[i].x, c->obj[i].y);
        }
        putchar('\n');
    }
     
   
    void print_clusters(struct cluster_t *carr, int narr)
    {
        printf("Clusters:\n");
        for (int i = 0; i < narr; i  )
        {
            printf("cluster %d: ", i);
            print_cluster(&carr[i]);
        }
    }
     
     
    int load_clusters(char *filename, struct cluster_t **arr){
     
        assert(arr != NULL);
        FILE * obj;
        assert(obj = fopen(filename, "r"));
     
        //count init for number of objects
        char tempcount[100]; char countnumbers[100]; int count;
        int numberstart; int counter = 0;
        fscanf(obj, "%s", tempcount);
        for(int i = 0; i<strlen(tempcount); i  ){
            if(tempcount[i] == '='){
                numberstart = i;
                break;
            }
        }
        for(int i = numberstart; i < strlen(tempcount); i  ){
            if(tempcount[i] >= 48 && tempcount[i] <= 57){
                countnumbers[counter] = tempcount[i];
                counter  ;
            }
        }
        assert(strlen(countnumbers) > 0);
        count = atoi(countnumbers);
     
        // Get ID, X, Y
        int id, x, y, pos = 0;
        struct obj_t point[count];
        while(fscanf(obj, "%d %d %d", &id, &x, &y) == 3) {
     
        // Build array
        point_ctor(&point[pos],id,x,y);
        arr[pos] = malloc(sizeof(struct obj_t));
        init_cluster(arr[pos],count);
        append_cluster(arr[pos], point[pos]);
     
     
     
     
        printf("Object %d at X%f Y%f\n", arr[pos]->obj[pos].id,arr[pos]->obj[pos].x, arr[pos]->obj[pos].y);
     
          pos  ;
       }
     
        fclose(obj);
     
        return 0;
    }
     
     
     
    int main(int argc, char *argv[])
    {
        struct cluster_t *cluster;
        char extension[4];
        strcpy(extension,".txt");
        char subor[100];
        strcpy(subor,argv[1]); 
        strcat(subor,extension);
     
        load_clusters(subor, &cluster);
        //print_clusters(&cluster[3],20);
     
     
        // Lloydov algoritmus
     
        
        return 0;
    }
     

the program is run: ./program objekty

objekty - name of file without .txt

An example of an input file: "objekty.txt":

 count=20
 40 86 663
 43 747 938
 47 285 973
 49 548 422
 52 741 541
 56 44 854
 57 795 59
 61 267 375
 62 85 874
 66 125 211
 68 80 770
 72 277 272
 74 222 444
 75 28 603
 79 926 463
 83 603 68
 86 238 650
 87 149 304
 89 749 190
 93 944 835

The problem seems to be at around in function append_cluster in line: c->obj[((c->size)-1)].id = obj.id; (line 150) A brief explanation before going through the code: Here are my structs:

```
struct obj_t {
    int id;
    float x;
    float y;
};

struct cluster_t {
    int size;
    int capacity;
    struct obj_t *obj;
};
```

Full code pastebin: https://pastebin.com/cffiDYBm

  1. I make an array of cluster_t structs in main(); (struct cluster_t *cluster;)

  2. I pass this array to a function load_clusters(filename, &cluster); Function def: int load_clusters(char *filename, struct cluster_t **arr)

  3. I do some code and pass an index of the cluster array to an append function append_cluster(arr[pos], point[pos]); this function effectively adds a point at the end of the array. (resizes if needed) Function def: void append_cluster(struct cluster_t *c, struct obj_t obj);

The problem: I need to be able to change data of a specific obj_t in a cluster_t array (cluster_t->obj[n]).

The results being that my code stopped running and the line was not processed. Is there any other way to do this? Is it a small change in syntax? I'm out of ideas.

I tried:

c->obj[(c->size)-1].id = obj.id;

Also I made a function which did this for me but I got the same results:

void obj_ctor(struct obj_t *p, struct obj_t obj){
    p->id = obj.id;
    p->x = obj.x;
    p->y = obj.y;
}

Here is the problem which should be as minimal as possible: (I'm trying to get both printfs on stdout)

#include <stdio.h>
#include <stdlib.h>
struct obj_t {
    int id;
    float x;
    float y;
};

struct cluster_t {
    int size;
    int capacity;
    struct obj_t *obj;
};
void obj_ctor(struct obj_t *p, struct obj_t obj){
    p->id = obj.id;
    p->x = obj.x;
    p->y = obj.y;
}
void pass(struct cluster_t *p, struct obj_t add){
    obj_ctor(&p->obj[0],add);
    p->size  = 1;
}
void pass1(struct cluster_t **arr){
    struct obj_t o3;
    o3.id = 1; o3.x = 2; o3.y = 3;
    int count = 20;
    int pos = 0;
    while(pos < 3){
    arr[pos]->capacity = 3;
    arr[pos]->size = 0;
    arr[pos]->obj = malloc(count*sizeof(struct obj_t));
    pass(arr[pos], o3);
    pos  ;
    }
}

int main(int argc, char *argv[])
{
    printf("Testing");
    struct cluster_t *test;
    pass1(&test);
    printf("GOT HERE");
}

CodePudding user response:

The final minimal example is nicely manageable — thank you. Here is a fairly straight-forward extension of that code. It is lazy in that it uses assert() to enforce necessary properties.

It includes a function to dump the data in a struct cluster_t structure. I regard such functions as a necessity — at the very least, they're extremely helpful. Quite often, I write them to take a FILE *fp argument so that messages can be written to standard output, standard error or to a log file, or, indeed, anywhere you can point a file stream. Often, I'd have a separate dump_obj() function that would be invoked from dump_cluster(), but it doesn't seem necessary here.

The key point is that it ensures that test.obj in main() points to an array of 3 struct obj_t. If you want dynamic memory allocation, changes are needed.

/* SO 7467-2430 */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

struct obj_t
{
    int id;
    float x;
    float y;
};

struct cluster_t
{
    int size;
    int capacity;
    struct obj_t *obj;
};

static void obj_ctor(struct obj_t *p, struct obj_t obj)
{
    p->id = obj.id;
    p->x = obj.x;
    p->y = obj.y;
}

static void pass(struct cluster_t *p, struct obj_t add)
{
    assert(p != NULL && p->obj != NULL);
    assert(p->size < p->capacity);
    obj_ctor(&p->obj[p->size], add);
    p->size  = 1;
}

static void dump_cluster(const char *tag, struct cluster_t *p)
{
    printf("%s (%p):\n", tag, p);
    if (p != NULL)
    {
        printf("size = %d, capacity = %d, objects = %p\n", p->size, p->capacity, p->obj);
        for (int i = 0; i < p->size; i  )
            printf("  [%d] id = %d, pos = (%g, %g)\n", i, p->obj[i].id, p->obj[i].x, p->obj[i].y);
    }
}

int main(void)
{
    printf("Testing\n");
    struct cluster_t test;
    struct obj_t o1, o2, o3;
    o1.id = 1;
    o2.id = 2;
    o3.id = 3;
    o1.x = 1;
    o2.x = 2;
    o3.x = 3;
    o1.y = 1;
    o2.y = 2;
    o3.y = 3;
    test.capacity = 3;
    test.size = 0;
    struct obj_t arr[3]; 
    test.obj = arr;

    pass(&test, o3);
    printf("GOT HERE\n");
    dump_cluster("After adding 1", &test);
    pass(&test, o2);
    pass(&test, o1);
    dump_cluster("After adding 3", &test);

    return 0;
}

Example output (the addresses will probably differ for you):

Testing
GOT HERE
After adding 1 (0x7ffeed15b3b0):
size = 1, capacity = 3, objects = 0x7ffeed15b3c0
  [0] id = 3, pos = (3, 3)
After adding 3 (0x7ffeed15b3b0):
size = 3, capacity = 3, objects = 0x7ffeed15b3c0
  [0] id = 3, pos = (3, 3)
  [1] id = 2, pos = (2, 2)
  [2] id = 1, pos = (1, 1)
  •  Tags:  
  • c
  • Related