Thread: Help with Static initializer in array

  1. #1
    Registered User
    Join Date
    Jun 2012
    Posts
    6

    Help with Static initializer in array

    HI ,

    I am implementing a function for my assignment based on the following information. As you see the main.c file has a function printWithoutDuplicates which prints the strings that are not printed previously. I can use static arrays for this.(Dont confuse with arrays on stack.)

    Code:
    #ifndef TKK_AS_C_PRINTERS_H
    #define TKK_AS_C_PRINTERS_H
    
    /* Prints strings without duplicates * This implies that the function must store all previously printed strings
     *  and not print a string it has already printed.
     * In case of duplicate, nothing is printed.
     * As with printWithIndex, a NULL parameter resets the storage and should
     *  free any memory allocated for the storage. */
    void printWithoutDuplicates(const char*);
    
    
    #endif
    Code:
    #include "printers.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <string.h>
    
    
    static char *arraylist;
    static int count = 0;
    
    
    
    void printWithoutDuplicates(const char* stringname) {
        bool flag = true;
        if (stringname) {
            if (count > 0) {
                for (int i = 0; i < count; i++) {
                    char *compare = arraylist[i];
                    if (!strcmp(stringname, compare)) {
                        flag = false;
                    }
                }
            } else {
                arraylist = malloc(sizeof (char));
                count = 1;
                arraylist[0] = stringname;
                flag = true;
            }
            
            
            if (flag){
                printf("%s\n", stringname);
                arraylist = realloc(arraylist, (sizeof (char) *(count + 1)));
                arraylist[count] = stringname;
                count = count + 1;
            }
        } else
            free(arraylist);
    }
    Code:
    #include "printers.h"
    
    
    #include <stdio.h>
    
    
    int main(void)
    {
      const char* strings[] = {"a string", "another string", "a string", "a better string", "a string", NULL};
    
    
      
      printf("Printing without duplicates\n");
      for (size_t i = 0;strings[i];i++)
        printWithoutDuplicates(strings[i]);
    
    
      printf("Resetting the duplicate storage\n");
      printWithoutDuplicates(NULL);
    }
    Printing the array gives error when I use the arraylist. Please tell me what to do and how to modify the code. I am stuck there.

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Printing the array gives error when I use the arraylist
    Post the complete error message, exactly as it appears in your development environment.

    Jim

  3. #3
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Your arraylist is not an array of strings, it is just one string. I think you are almost on the right track, however.

    What I recommend doing, is using a pointer to a large string area, and an array of offsets to that area. You do not want to use pointers, because then you'd have to adjust them all when resizing the string area dynamically. Something like this:
    Code:
    struct ref {
        size_t         offset;  
        size_t         length;
    };
    
    static size_t      area_size = 0; /* chars allocated for area */
    static size_t      area_used = 0;
    static char       *area = NULL;
    
    static size_t      unique_size = 0; /* number of refs allocated */
    static size_t      unique_used = 0;
    static struct ref *unique = NULL;
    
    /* Note: string_pointer == area + unique[stringno]->offset
     *       0 <= stringno < unique_used
     *       0 <= unique[stringno]->offset < area_used
     *       0 <= unique[stringno]->offset + unique[stringno]->length <= area_used
    */
    The variables are marked static so that they are directly accessible only within this compilation unit; their contents will be dynamically allocated.

    Here, unique defines the unique strings (offset and length in area), and area contains the actual string contents.

    To resize the area use
    Code:
    {
        const size_t new_area_size = area_used + more; /* Grow by more */
        char *new_area;
    
        if (new_area_size < area_size) {
            return Error: Size overflows. Cannot grow area.
        }
    
        new_area = realloc(area, new_area_size);
        if (!new_area) {
            return Error: Out of memory. Old area is still accessible.
        }
    
        area_size = new_area_size;
        area = new_area;
    }
    but remember that more should most likely include room for an extra NUL byte for each string, since most C library string functions expect strings to end at a NUL.

    The Error cases should abort the function at least -- or the entire program, considering how difficult it is to recover from running out of memory.

    To grow unique by more new string references, you can use
    Code:
    {
        const size_t new_unique_size = unique_used + more;
        const size_t new_bytes = new_unique_size * sizeof (struct ref);
        struct ref *new_unique;
    
        if (new_bytes / sizeof (struct ref) != new_unique_size) {
            return Error: size overflows. Cannot allocate more string refs.
        }
    
        new_unique = realloc(unique, new_bytes);
        if (!new_unique) {
            return Error: Out of memory. Old unique is still accessible.
        }
    
        unique_size = new_unique_size;
        unique = new_unique;
    }
    Note that if the reallocation fails, the old data is still accessible.

    Because the pointers are initialized to NULL, and the sizes to zeros, there is no need to use malloc(size) for the initial case: realloc(NULL,size) is the exact same thing.

    There are a large number of techniques you can use later on to make all this more efficient, for example by adding a hash value to the string reference and keeping the unique sorted by hash, and/or by making unique a hash table or a tree instead. Hashing means you don't need to compare the string contents unless they have the same length and their hashes match. Using a tree makes insertions cheaper, but the code is more complex (and there are a number of tree types you could choose from).

    Does this help you?

  4. #4
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Your compiler should be screaming warnings when you build this code. Check the warnings and heed them - they indicate the lines you should analyze.

    Code:
    arraylist = malloc(sizeof (char));
    You're only allocating one byte of memory here. You should allocate the length of the string passed to the function (don't forget about the null character).

    Code:
    arraylist = realloc(arraylist, (sizeof (char) *(count + 1)));
    Ditto.

    Code:
    char *compare = arraylist[i];
    if (!strcmp(stringname, compare))
    {
        //
    }
    I don't see a use for the temporary "compare" string - why not just compare directly with the string from "arraylist"?

    Code:
    arraylist[0] = stringname;
    // ...
    arraylist[count] = stringname;
    // ...
    Assigning strings in such a fashion is not valid in C. Consider using "strcpy()" instead.

    There's more I could say, but this is a good start.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 03-21-2012, 01:14 AM
  2. initialize member array in initializer list?
    By Vick jr in forum C++ Programming
    Replies: 4
    Last Post: 05-20-2010, 06:39 AM
  3. 3D array initializer list
    By kenryuakuma in forum C# Programming
    Replies: 5
    Last Post: 11-15-2009, 01:40 AM
  4. warning: excess elements in array initializer
    By redruby147 in forum C Programming
    Replies: 6
    Last Post: 09-30-2009, 06:08 AM
  5. Array problem - inavlid initializer
    By Shadow in forum C++ Programming
    Replies: 3
    Last Post: 09-02-2002, 01:40 PM