Thread: Managing a dynamic array of structures

  1. #16
    Registered User
    Join Date
    Oct 2012
    Posts
    42
    That makes sense, then I use
    Code:
    while (fgets(test, sizeof(test), data) != NULL)
    to read one line of the file in at a time and then put that line into the test character array, then I use
    Code:
    sscanf(test, "%s %s %s %s", text1, text2, text3, text4);
    to parse the different sections of that character array into smaller character arrays.
    Since I can't use fscanf to append the data into the structure, I tried using
    Code:
            if (strcmp(text1, "I") == 0) {
                printf("Friend Added!\n");
                friends[i].IDP = text;
                friends[i].first = text2;
                friends[i].last = text3;
                friends[i].phone = text4;
    but that doesn't seem to work (it gives me an "incompatible types" error in the compiler).

  2. #17
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Look up strlcpy() or strncpy().

  3. #18
    Registered User
    Join Date
    Oct 2012
    Posts
    42
    Ah, thank you! That makes sense. Now it looks like:

    Code:
     while (fgets(test, sizeof(test), data) != NULL) {
            sscanf(test, "%s %s %s %s", text1, text2, text3, text4);
            if (strcmp(text1, "I") == 0) {
                printf("Friend Added!\n");
                strncpy(friends[i].IDP, text1, sizeof(text2));
                strncpy(friends[i].first, text2, sizeof(text2));
                strncpy(friends[i].last, text3, sizeof(text2));
                strncpy(friends[i].phone, text4, sizeof(text2));
                k++;
                i++;
                // Resize the array every 3 additions.
    It correctly adds all lines with I to the dynamic array of structures and skips adding lines with P or D, and then correctly prints out the entire array thus far when it encounters a P. Now I just have to work out how to write the delete function for when it happens upon a D. I'm thinking something like a loop to search the array for the matching line, then using strncpy() to "delete" the found line.

  4. #19
    Registered User
    Join Date
    Oct 2012
    Posts
    42
    Also, I need to sort the array of structures by first name (A-Z) every time a new contact is added. How would I go about doing that?

  5. #20
    Registered User
    Join Date
    Oct 2012
    Posts
    42
    Alright, I was able to finish the delete function:
    Code:
            else if (strcmp(text1, "D") == 0) {
                printf("Finding friend to delete...\n");
                // Find and delete friend.
                for (l = 0; l < i; l++) {
                    if (strcmp(text2, friends[l].first) == 0 && 
                        strcmp(text3, friends[l].last) == 0  &&
                        strcmp(text4, friends[l].phone) == 0) 
                    {
                        printf("Found friend! Deleting...\n");
                        for (m = l; m < i; m++) {
                            strncpy(friends[m].IDP, friends[m+1].IDP, sizeof(text1));
                            strncpy(friends[m].first, friends[m+1].first, sizeof(text2));
                            strncpy(friends[m].last, friends[m+1].last, sizeof(text2));
                            strncpy(friends[m].phone, friends[m+1].phone, sizeof(text2));
                        }
                    }
                    
                }            
            }
    Seems to work just fine, although it leaves spaces in the output where an entry was deleted, but I don't think that's a huge problem.

    I started on my alphabetical sort for each time a new contact is added to friends, and here's what I have so far:
    Code:
    while (fgets(test, sizeof(test), data) != NULL) {
            sscanf(test, "%s %s %s %s", text1, text2, text3, text4);
            if (strcmp(text1, "I") == 0) {
                printf("Friend added!\n");
                strncpy(friends[i].IDP, text1, sizeof(text2));
                strncpy(friends[i].first, text2, sizeof(text2));
                strncpy(friends[i].last, text3, sizeof(text2));
                strncpy(friends[i].phone, text4, sizeof(text2));
                k++;
                temp = (struct list *)calloc(length, sizeof(struct list));
                for (j = 0; j < i; j++) {
                    if(strcmp(friends[j].first, friends[j+1].first) > 0) {
                        *temp = friends[j];
                        friends[j] = friends[j+1];
                        friends[j+1] = *temp;
                    }
                }
                free(temp);
                i++;
    It sorts the names, but not in alphabetical output at all. Using this data file:
    Code:
    I Ron Marsh 701-222-3333
    I Dave Marsh 218-444-6666
    I Radell Marsh 701-235-8133
    I Brenda Marsh 701-277-5050
    I Herbert Marsh 701-552-5231
    I Kyle Marsh 701-224-2452
    I Kia Marsh 701-275-1234
    I Steve Marsh 701-275-0987
    I Paul Marsh 701-276-0987
    D Herbert Marsh 701-552-5231
    I Sheila Marsh 701-277-0987
    I Rick Marsh 701-278-0987
    I Gregory Marsh 701-279-0987
    I Keith Marsh 701-275-0987
    P
    I Shirley Marsh 701-275-0987
    I Bobby Marsh 701-275-0987
    I Junior Marsh 701-275-0987
    D Rick Marsh 701-278-0987
    I Peter Marsh 701-275-0987
    I Hanson Marsh 701-275-0987
    I Frank Marsh 701-275-0987
    I Seth Marsh 701-275-0987
    I David Marsh 701-275-0987
    P
    the output is this:

    Code:
    C:\cygwin\home\Paul>a.exe
    Number of lines in input file: 24
    Friend added!
    Friend added!
    Friend added!
    Resizing list...
    Friend added!
    Friend added!
    Friend added!
    Resizing list...
    Friend added!
    Friend added!
    Friend added!
    Resizing list...
    Finding friend to delete...
    Found friend! Deleting...
    Friend added!
    Friend added!
    Friend added!
    Resizing list...
    Friend added!
    Printing List!
    Brenda Marsh 701-277-5050
    Dave Marsh 218-444-6666
    Kia Marsh 701-275-1234
    Kyle Marsh 701-224-2452
    
    Paul Marsh 701-276-0987
    Radell Marsh 701-235-8133
    Rick Marsh 701-278-0987
    Ron Marsh 701-222-3333
    Gregory Marsh 701-279-0987
    Sheila Marsh 701-277-0987
    Keith Marsh 701-275-0987
    Steve Marsh 701-275-0987
    Friend added!
    Friend added!
    Resizing list...
    Friend added!
    Finding friend to delete...
    Found friend! Deleting...
    Friend added!
    Friend added!
    Resizing list...
    Friend added!
    Friend added!
    Friend added!
    Resizing list...
    Printing List!
    
    Brenda Marsh 701-277-5050
    Dave Marsh 218-444-6666
    Gregory Marsh 701-279-0987
    Keith Marsh 701-275-0987
    Kia Marsh 701-275-1234
    Bobby Marsh 701-275-0987
    Kyle Marsh 701-224-2452
    Junior Marsh 701-275-0987
    Paul Marsh 701-276-0987
    
    Peter Marsh 701-275-0987
    Radell Marsh 701-235-8133
    Hanson Marsh 701-275-0987
    Ron Marsh 701-222-3333
    Frank Marsh 701-275-0987
    Sheila Marsh 701-277-0987
    Seth Marsh 701-275-0987
    Shirley Marsh 701-275-0987
    David Marsh 701-275-0987
    Steve Marsh 701-275-0987
    
    C:\cygwin\home\Paul>
    As you can see, the output is in a different order than original, but it's not A-Z (based off first name) at all. There's also those ugly blank spaces, but as I said I don't think that's the issue with the alphabetical sorting.

  6. #21
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I think your delete is really close.

    What I think you did right:
    You want to shift the rest of the array by -1 place starting from the place of the old contact.

    What you did wrong:
    Basically this means that the portion of the array you've used will be one element less, so you need to update the appropriate variables afterward.

    And you need to loop over the array correctly. For any part of the shift you will move element i+1 to i, which means that at the end, when the counter is at the highest index, you do not want to access highest and highest+1. The element highest+1 is out of bounds, and accessing an array out of bounds is undefined behavior.


    As for sorting, there are plenty of algorithms that have been around for decades. I say pick one, like insert sort, and implement it. Plus, insert sort works well with almost sorted data, so it seems perfect for the kind of situation you're in.

    You might be clever and notice that part of what you're doing in insert sort is shifting, which you also do in deletion, and be able to factor that code out into its own function.

  7. #22
    Registered User
    Join Date
    Oct 2012
    Posts
    42
    Alright, I finished it (well, I think so...I tested it with a multitude of different data files and it doesn't crash)!

    Code:
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <ctype.h> 
    #include <string.h> 
     
    int main(void) {
    
       // Build friends structure. 
       struct list{ 
           char IDP[10]; 
           char first[42]; 
           char last[42]; 
           char phone[42]; 
       } *friends, *temp;
    
       // Define variables. 
       int   j, l, m, n, a, b, c; 
       int   i = 0; 
       int   base = 10; 
       int   length = 10; 
       char  text1[10], text2[42], text3[42], text4[42], test[136]; 
       FILE *data; 
    
        // Open data file.    
        data = fopen("./hw4.data", "r"); 
     
        // Create dynamic array of structures. 
         friends = (struct list *)calloc(base, sizeof(struct list)); 
         
        // Populate dynamic array, deleting, adding and resizing when needed. 
        while (fgets(test, sizeof(test), data) != NULL) { 
            sscanf(test, "%s %s %s %s", text1, text2, text3, text4);
            //printf("Size of length: %d\n", length);  // For testing.
            //printf("Size of array: %d\n", i);        // For testing. 
            if (strcmp(text1, "I") == 0) { 
                printf("Friend added!\n"); 
                strncpy(friends[i].IDP, text1, sizeof(text2)); 
                strncpy(friends[i].first, text2, sizeof(text2)); 
                strncpy(friends[i].last, text3, sizeof(text2)); 
                strncpy(friends[i].phone, text4, sizeof(text2));
                // Sort dynamic array thus far alphabetically. 
                temp = (struct list *)calloc(length, sizeof(struct list));
                for (n = i; n >= 0; n--) { 
                   for (j = n; j < i; j++) { 
                       if(strcmp(friends[j].first, friends[j+1].first) > 0) { 
                           *temp = friends[j]; 
                           friends[j] = friends[j+1]; 
                           friends[j+1] = *temp; 
                       } 
                   }
                } 
                free(temp); 
                i++; 
                // Resize the array every 3 additions past the original length of 10. 
               if (length - i == 0) { 
                    printf("Resizing list...\n"); 
                    temp = (struct list *)calloc(length+3, sizeof(struct list));       // Make temp dynamic array. 
                    memcpy(temp, friends, sizeof(struct list)*length);                       // Copy friends data to temp array. 
                    free(friends);                                                                    // Free friends array. 
                    friends = (struct list *)calloc(length+3, sizeof(struct list));   // Remake friends dynamic array. 
                    memcpy(friends, temp, sizeof(struct list)*length);                        // Copy resized temp array back into friends array. 
                    length+=3;                                                                         // Increment and record new length.                      
               } 
            } 
            else if (strcmp(text1, "P") == 0) { 
                printf("Printing List!\n");
                printf("*----------------------------*\n"); 
                // Prints entire dynamic array thus far. 
                for (j = 0; j < i; j++) { 
                    printf("%s %s %s\n", friends[j].first, friends[j].last, friends[j].phone); 
                }
                printf("*----------------------------*\n"); 
            } 
            else if (strcmp(text1, "D") == 0) { 
                printf("Finding friend to delete...\n"); 
                // Find and delete friend. 
                for (l = 0; l < i; l++) { 
                    if (strcmp(text2, friends[l].first) == 0 &&  
                        strcmp(text3, friends[l].last) == 0  && 
                        strcmp(text4, friends[l].phone) == 0)  
                    { 
                        printf("Found! Deleting friend and decreasing list size...\n");
                        // Deletes friend from dynamic array. 
                        for (m = l; m < i; m++) { 
                            strncpy(friends[m].IDP, friends[m+1].IDP, sizeof(text1)); 
                            strncpy(friends[m].first, friends[m+1].first, sizeof(text2)); 
                            strncpy(friends[m].last, friends[m+1].last, sizeof(text2)); 
                            strncpy(friends[m].phone, friends[m+1].phone, sizeof(text2)); 
                        }
                        break; 
                    } 
                     
                }
                   i--;
                    length--;
                    // Same as above resize function only moves the entire  friends array into a new array of -1 size (decreases array size).    
                    temp = (struct list *)calloc(length, sizeof(struct list)); 
                    memcpy(temp, friends, sizeof(struct list)*length);                     
                    free(friends);                                                     
                    friends = (struct list *)calloc(length, sizeof(struct list)); 
                    memcpy(friends, temp, sizeof(struct list)*length);    
                    free(temp); 
            } 
     
        } 
            
         // Close data file. 
        fclose(data); 
         
        // Free dynamic array. 
        free(friends); 
        return 0; 
    }
    Thanks everyone for the help! I'm sorry I ask so many questions, I'm still a beginner at C (or any type of prorgramming) and I still don't know a lot of the methods or commands.

    P.S.
    Whiteflags, I know that I didn't do the optimization you stated when I resize the array, the reason is I understand why it works how I did it, and I wasn't really understanding how your optimization worked, so I didn't want to implement it until I fully understand why it works.

  8. #23
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    You don't need to do a second copy on the resize:

    Code:
            temp = (struct list *)calloc(length, sizeof(struct list)); 
            memcpy(temp, friends, sizeof(struct list)*length);                     
            free(friends);                                                     
            friends = temp;
            temp = NULL;

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamic Array Of Structures - Often Changing - HOW?
    By roadhogbob in forum C Programming
    Replies: 5
    Last Post: 01-04-2012, 04:17 PM
  2. Replies: 10
    Last Post: 12-03-2011, 02:26 PM
  3. Replies: 2
    Last Post: 07-11-2008, 07:39 AM
  4. dynamic array of structures
    By cjam in forum C++ Programming
    Replies: 2
    Last Post: 03-12-2004, 03:18 PM
  5. Managing a heap using an array.
    By rahuls in forum C Programming
    Replies: 3
    Last Post: 03-20-2003, 02:49 PM