Page 2 of 2 FirstFirst 12
Results 11 to 15 of 15

Thread: dynamic arrays in structs c

  1. #11
    Join Date
    Feb 2009
    Beans
    1,469

    Re: dynamic arrays in structs c

    You're very close. Here's a question for you that might help you find the solution: where and how are you going to call free() on the pointer returned by the malloc() in getRows()?

    It might help, if you're stuck, to draw pictures to represent your data structures. E.g., `conn' is an arrow (a pointer) that points to a box (a struct) that contains `file' and a pointer `db', which is an arrow pointing to another box that contains `rows', etc.

  2. #12
    Join Date
    Jan 2012
    Beans
    161

    Re: dynamic arrays in structs c

    is *conn->db->rows a pointer to rows? or is it an array of conn->db->rows

  3. #13
    Join Date
    Jan 2012
    Beans
    161

    Re: dynamic arrays in structs c

    just found out about calloc.....going to mess around with this....

  4. #14
    Join Date
    Jan 2012
    Beans
    161

    Talking Re: dynamic arrays in structs c

    Code:
    /*
     * ex17.c
     * 
     * Copyright 2014 Ronald C. Reid <ronald@laptop1>
     * 
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     * 
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     * 
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
     * MA 02110-1301, USA.
     * 
     * 
     */
    
    
    #include <stdio.h>
    #include <assert.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    
    
    
    
    
    struct Address {
        int id;
        int set;
        char *name;
        char *email;
    };
    
    struct Database {
        struct Address *rows;
    };
    
    struct Connection {
        FILE *file;
        struct Database *db;
    };
    
    int getTotal(const char *ptr)
    {
        int i;
        int total = 0;
        for(i = 0; *ptr++ != '\0'; i++){
            total++;
        }
        
        return total;
    }
    
    int getTotalRows(struct Address *addr)
    {
        int i;
        int total = 0;
        for(i = 0; !addr++; i++){
            total++;
        }
        return total;
    }
    
    void die(const char *message)
    {
        if(errno) {
            perror(message);
        } else {
            printf("ERROR: %s\n", message);
        }
    
        exit(1);
    }
    
    void Address_print(struct Address *addr)
    {
        printf("%d %s %s\n",
                addr->id, addr->name, addr->email);
    }
    
    void Database_load(struct Connection *conn)
    {
        int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
        if(rc != 1) die("Failed to load database.");
    }
    
    struct Connection *Database_open(const char *filename, char mode)
    {
        struct Connection *conn = malloc(sizeof(struct Connection));
        if(!conn) die("Memory error");
    
        conn->db = malloc(sizeof(struct Database));
        if(!conn->db) die("Memory error");
    
        if(mode == 'c') {
            conn->file = fopen(filename, "w");
        } else {
            conn->file = fopen(filename, "r+");
    
            if(conn->file) {
                Database_load(conn);
            }
        }
    
        if(!conn->file) die("Failed to open the file");
    
        return conn;
    }
    
    void Database_close(struct Connection *conn)
    {
        if(conn) {
            if(conn->file) fclose(conn->file);
            if(conn->db) free(conn->db);
            free(conn);
        }
    }
    
    void Database_write(struct Connection *conn)
    {
        rewind(conn->file);
    
        int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
        if(rc != 1) die("Failed to write database.");
    
        rc = fflush(conn->file);
        if(rc == -1) die("Cannot flush database.");
    }
    
    void Database_create(struct Connection *conn)
    {
        int i = 0;
        int x;
        printf("How many items do you want in the database?\n");
        scanf("%d", &x);
        conn->db->rows = calloc(x, sizeof(struct Address));
        for(i = 0; i < x; i++) {
            printf("Run number %d\n", i);
            getchar();
            // make a prototype to initialize it
            struct Address addr = {.id = i, .set = 0};
            printf("Debug statement. line 149 after the prototype of Address is set.");
            getchar();
            // then just assign it
            conn->db->rows[i] = addr;
        }
        printf("DEBUG.  Line 150.  I is now %d\n", i);
        getchar(); 
    }
    
    void Database_set(struct Connection *conn, int id, const char *name, const char *email)
    {
        struct Address *addr = &conn->db->rows[id];
        if(addr->set) die("Already set, delete it first");
    
        addr->set = 1;
        // WARNING: bug, read the "How To Break It" and fix this
        char *res = strncpy(addr->name, name, getTotal(name));
        // demonstrate the strncpy bug
        if(!res) die("Name copy failed");
    
        res = strncpy(addr->email, email, getTotal(email));// need total function here to get size of email!
        if(!res) die("Email copy failed");
    }
    
    void Database_get(struct Connection *conn, int id)
    {
        struct Address *addr = &conn->db->rows[id];
    
        if(addr->set) {
            Address_print(addr);
        } else {
            die("ID is not set");
        }
    }
    
    void Database_delete(struct Connection *conn, int id)
    {
        struct Address addr = {.id = id, .set = 0};
        conn->db->rows[id] = addr;
    }
    
    void Database_list(struct Connection *conn)
    {
        int i = 0;
        struct Database *db = conn->db;
    
        
        for(i = 0; i < getTotalRows(conn->db->rows); i++) {
            struct Address *cur = &db->rows[i];
    
            if(cur->set) {
                Address_print(cur);
            }
        }
    }
    
    int main(int argc, char *argv[])
    {
        if(argc < 3) die("USAGE: ex17 <dbfile> <action> [action params]");
    
        char *filename = argv[1];
        char action = argv[2][0];
        struct Connection *conn = Database_open(filename, action);
        int id = 0;
    
        if(argc > 3) id = atoi(argv[3]);
        if(id >= getTotalRows(conn->db->rows)) die("There's not that many records.");//need that function to compute total number of rows here!
    
        switch(action) {
            case 'c':
                Database_create(conn);
                Database_write(conn);
                break;
    
            case 'g':
                if(argc != 4) die("Need an id to get");
    
                Database_get(conn, id);
                break;
    
            case 's':
                if(argc != 6) die("Need id, name, email to set");
    
                Database_set(conn, id, argv[4], argv[5]);
                Database_write(conn);
                break;
    
            case 'd':
                if(argc != 4) die("Need id to delete");
    
                Database_delete(conn, id);
                Database_write(conn);
                break;
    
            case 'l':
                Database_list(conn);
                break;
            default:
                die("Invalid action, only: c=create, g=get, s=set, d=del, l=list");
        }
    
        Database_close(conn);
    
        return 0;
    }

    GETTING BETTER!!!!!

  5. #15
    Join Date
    Feb 2009
    Beans
    1,469

    Re: dynamic arrays in structs c

    Congrats!

    (Don't forget to free() it...)

    Strictly speaking, calloc() isn't necessary here; since you don't need it zeroed, malloc(x * sizeof(struct Address)) would work as well (marginally faster, probably). But the most important part is figuring out how to declare and initialize the pointer and it looks like you figured that out already.

Page 2 of 2 FirstFirst 12

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •