Thread: Creating and Using a dynamic array of C strings?

  1. #1
    Registered User
    Join Date
    Apr 2005
    Posts
    13

    Creating and Using a dynamic array of C strings?

    Hello, I have this program where I'm creating a list of strings and the list can expand to create more strings. The reason is because users can add words during runtime, and so it needs to be expandable. The size of the word is guaranteed to be less than 100, so I've allocated memory to be a little above 100 for each word.

    The code seems to work find, but... it keeps crashing whenever I try to retrieve a string. Any help?

    Code:
    /*Some standard headers that have been omitted*/
    
    #define STRING_MAX 102
    #define FALSE 0
    #define TRUE 1
    
    #define ARTICLE 0
    #define NOUN 1
    #define VERB 2
    #define PREPOSITION 3
    
    char **preps;
    char **nouns;
    char **verbs;
    char **arts;
    int numWords[4];
    
    void allocateWords(char ** words, int type)
    {
        int size_x = numWords[type];
    
        int size_y = STRING_MAX;
     
    int i=0;
    
    if ( (words = (char **)malloc(size_x * sizeof(char *)) ) == NULL )
        {
        printf("\nError, memory not allocated.\n");
        exit(1);
        }
    
    for (i = 0; i < size_x; i++)
        *(words+i) = (char *)malloc(size_y * sizeof(char));
    
    }
    
    void addWord(char ** words, int type, char word[])
    {
        numWords[type]++;
        words = (char **) realloc(words, numWords[type]);
        *(words+(numWords[type]-1)) = word;
    }
    
    void displayWords(char ** words, int type)
    {
    
        int i;
        if(*(words+0) == NULL) printf("It's null");
        else
            printf("%s", *(words+0));
    }
    
    int main(int argc, char *argv[])
    {
      memset(choice, 0, 3);
      memset(numWords, 0, 4);
    
      allocateWords(preps, PREPOSITION);
      addWord(preps, PREPOSITION, "Yours");
      displayWords(preps, PREPOSITION);
      return 0;
     }
    It keeps running until is gets to "displayWords" and then the program crashes when I try to retrieve an element. The allocation and addWord functions might be at fault, especially since I've never worked with malloc, realloc and multi-pointers before or even passing multi-pointers to functions.

  2. #2
    DESTINY BEN10's Avatar
    Join Date
    Jul 2008
    Location
    in front of my computer
    Posts
    804
    Where is your 'choice' variable declared? Casting malloc is redundant. It already returns void*.
    HOPE YOU UNDERSTAND.......

    By associating with wise people you will become wise yourself
    It's fine to celebrate success but it is more important to heed the lessons of failure
    We've got to put a lot of money into changing behavior


    PC specifications- 512MB RAM, Windows XP sp3, 2.79 GHz pentium D.
    IDE- Microsoft Visual Studio 2008 Express Edition

  3. #3
    Registered User
    Join Date
    Apr 2005
    Posts
    13
    Quote Originally Posted by BEN10 View Post
    Where is your 'choice' variable declared? Casting malloc is redundant. It already returns void*.
    I forgot to delete choice. It's non-essential to the problem parts.

    But, if you want, this was at top.

    int choice[3];

    Is the redundancy the source of error?

  4. #4
    DESTINY BEN10's Avatar
    Join Date
    Jul 2008
    Location
    in front of my computer
    Posts
    804
    Quote Originally Posted by swbluto View Post
    I forgot to delete choice. It's non-essential to the problem parts.

    But, if you want, this was at top.

    int choice[3];

    Is the redundancy the source of error?
    In the function displayWords, you're checking if *(words+0)==NULL, but actually *words corresponds to where the first char of the string is stored not the address where the string's address is stored. So, change this if condition to
    Code:
    if((words+0)==NULL)
    //do  whatever
    I dont know if I'm understood or not but this will remove your problem. Also casting malloc is not an error but not according to the C standards.
    Last edited by BEN10; 11-17-2009 at 02:19 AM.
    HOPE YOU UNDERSTAND.......

    By associating with wise people you will become wise yourself
    It's fine to celebrate success but it is more important to heed the lessons of failure
    We've got to put a lot of money into changing behavior


    PC specifications- 512MB RAM, Windows XP sp3, 2.79 GHz pentium D.
    IDE- Microsoft Visual Studio 2008 Express Edition

  5. #5
    Registered User
    Join Date
    Apr 2005
    Posts
    13
    It still crashes.

    Here's the entire code with all the headers and other info, just in case it might be of interest. The other code isn't producing a problem, however, because the program doesn't crash unless the displayWords() function is executed.




    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <string.h>
    
    #include <sys/types.h>
    #include <sys/stat.h>
    
    
    #define STRING_MAX 102
    #define FALSE 0
    #define TRUE 1
    
    #define ARTICLE 0
    #define NOUN 1
    #define VERB 2
    #define PREPOSITION 3
    
    char **preps;
    char **nouns;
    char **verbs;
    char **arts;
    int numWords[4];
    
    
    int choice[3];
    char inputFileStr[STRING_MAX];
    FILE * inputFile;
    
    void allocateWords(char ** words, int type)
    {
        int size_x = numWords[type];
    
        //This will be determined by the word culling.
        int size_y = STRING_MAX;
         // memset(numWords, 0, 4);
    
    
    
          int *a;
    int i=0;
    
    if ( (words = (char **)malloc(size_x * sizeof(char *)) ) == NULL )
        {
        printf("\nError, memory not allocated.\n");
        exit(1);
        }
    
    for (i = 0; i < size_x; i++)
        *(words+i) = (char *)malloc(size_y * sizeof(char));
    
    //Now fill the words in the dynamically allocated array;
    //a[0] = "what";
    //a[1] = "cool";
    
    }
    
    void addWord(char ** words, int type, char word[])
    {
        numWords[type]++;
        words = (char **) realloc(words, numWords[type]);
        *(words+(numWords[type]-1)) = word;
    }
    
    void displayWords(char ** words, int type)
    {
    
        int i;
        if((words+0) == NULL) printf("It's null");
        else
            printf("%s", (words+0));
        /**//*
        for(i=0; i<numWords[type];i++)
        {
            printf("%s ", words[i]);
        }
        */
    
    }
    
    void displayMainMenu()
    {
        printf("\n   ");
        printf("\nPlease choose from the following: ");
        printf("\n1) Generate a Sentence ");
        printf("\n2) Display all words ");
        printf("\n3) Add a word ");
        printf("\n4) Delete a word ");
        printf("\n5) Display all words sorted ");
        printf("\n6) Exit the program");
        printf("\nChoice --> ");
    }
    
    void getChoice(int numOptions, int * tempChoice)
    {
        scanf("%i", tempChoice);
        while(*tempChoice<1 || *tempChoice>numOptions)
        {
            printf("\n\nEnter a correct choice --> ");
            scanf("%i", tempChoice);
        }
    }
    
    void cullFile(FILE * iFile)
    {
    
    }
    
    char ** test;
    
    int main(int argc, char *argv[])
    {
      memset(choice, 0, 3);
      memset(numWords, 0, 4);
    
      allocateWords(preps, PREPOSITION);
      addWord(preps, PREPOSITION, "Yours");
      //displayWords(preps, PREPOSITION);
      printf("%s",*preps);
      /*
      **test = 'c';
      printf("%c", **test);
      */
    
      printf("Welcome to the Random Sentence Generator \n\n");
      printf("Please enter the name of the input file: ");
    
      scanf("%s",inputFileStr);
      while((inputFile = fopen(inputFileStr, "r")) == NULL)
      {
            printf("\n\nPlease enter the name of the input file: ");
            scanf("%s",inputFileStr);
      };
    
      //cullFile(inputFile);
    
      while(choice[0] != 6)
      {
        displayMainMenu();
        getChoice(6, &choice[0]);
        if(choice[0] == 1)
        {
           // generateSentence();
        }
        else if(choice[0] == 2)
        {
           // displayAllWords();
        }
        else if(choice[0] == 3)
        {
          //  addAWord();
        }
        else if(choice[0] ==4)
        {
          //  deleteAWord();
        }
        else if(choice[0] ==5)
        {
           // displayAllSorted();
        }
        else if(choice[0] ==6)
           break;
        /*
        scanf("%i", &choice[0]);
        while(choice[0]<1 || choice[0]>6)
        {
            printf("\n\nEnter a correct choice --> ");
            scanf("%i", &choice[0]);
        }
        */
    
    
      }
    
      printf("Thank you and have a nice day. Goodybe. :) \n\n");
    
      system("PAUSE");
      return 0;
    }

  6. #6
    DESTINY BEN10's Avatar
    Join Date
    Jul 2008
    Location
    in front of my computer
    Posts
    804
    In main after calling addWord function do this:
    Code:
    printf("%s",preps);
    HOPE YOU UNDERSTAND.......

    By associating with wise people you will become wise yourself
    It's fine to celebrate success but it is more important to heed the lessons of failure
    We've got to put a lot of money into changing behavior


    PC specifications- 512MB RAM, Windows XP sp3, 2.79 GHz pentium D.
    IDE- Microsoft Visual Studio 2008 Express Edition

  7. #7
    Registered User
    Join Date
    Apr 2005
    Posts
    13
    Quote Originally Posted by BEN10 View Post
    In main after calling addWord function do this:
    Code:
    printf("%s",preps);
    I did and it actually didn't crash! It outputs...

    <null>

    Now it'd help to understand what exactly is null. Preps is a char** and I believe strings are a char*, so maybe it has something to do with that?

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    "preps" is a pointer. A pointer with a value of NULL has no memory allocated to it.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    DESTINY BEN10's Avatar
    Join Date
    Jul 2008
    Location
    in front of my computer
    Posts
    804
    preps points to nothing(i.e NULL pointer). By doing *preps you're trying to access the NULL memory which is an error. For eg.
    Code:
    	int *s=NULL;
    	printf("%p",(void *)s); // will not show any error, will simply print NULL
    	printf("%d",*s); // error coz trying to read NULL location
    By the way I haven't read your whole code so I can't tell you in detail what's all happening.
    HOPE YOU UNDERSTAND.......

    By associating with wise people you will become wise yourself
    It's fine to celebrate success but it is more important to heed the lessons of failure
    We've got to put a lot of money into changing behavior


    PC specifications- 512MB RAM, Windows XP sp3, 2.79 GHz pentium D.
    IDE- Microsoft Visual Studio 2008 Express Edition

  10. #10
    Registered User
    Join Date
    Apr 2005
    Posts
    13
    Ok, so if it's null, then that means it hasn't been allocated? But that was supposedly allocated in the allocateWords function with the following code...

    Code:
    if ( (words = (char **)malloc(size_x * sizeof(char *)) ) == NULL )
        {
        printf("\nError, memory not allocated.\n");
        exit(1);
        }
    
    for (i = 0; i < size_x; i++)
        *(words+i) = (char *)malloc(size_y * sizeof(char));
    Trying to simplify it as much as possible to get to the problem, let's just place the allocation code inside the main function. Would this work?

    Code:
    preps = (char **)malloc(2 * sizeof(char *)); //allocated two pointers for a two strings, one for each string
    *preps = (char*)malloc(102*sizeof(char));//point first pointer to a string / char block of memory
    And then how would I add a words to preps?

    Would I do *preps = "up", and then retrieve it using *preps?

    EDIT: Ok, so I tested it, and that's precisely what needed to be done. BUT, it seems like I'm doing exactly that inside the function (I just copied and pasted and changed words to preps, and took away the for loop.). Can I not allocate memory inside a function to a double pointer? Does it "disappear" when the function call ends? If so, how would I combat this? Here's the code I tested...

    Code:
    preps = (char **)malloc(2 * sizeof(char *));
      *preps = (char*)malloc(102*sizeof(char));
      *preps = "up";
      *(preps+1) = "down";
      printf("%s and %s",*preps, *(preps+1));
    This prints up and down like I expected when put directly inside the main function.

    EDIT:

    I think I "should have" included

    *(preps+1) = (char*)malloc(102*sizeof(char));

    before defining

    *(preps+1) = "down"

    But for some reason it works in the code. I wonder if the original code is really "incorrect" but I just got lucky? Or does defining *(preps+1) = "down" automatically use malloc to allocate the memory?
    Last edited by swbluto; 11-17-2009 at 12:06 PM.

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by swbluto View Post
    does defining *(preps+1) = "down" automatically use malloc to allocate the memory?
    Yes, because *(preps+1) is still an uninitialized pointer, so that is the equivalent of:
    Code:
    char *eg="hello world";
    1) You can ONLY do this with an uninitialized pointer.
    2) You cannot modify the contents of "eg" after this, nor should you reassign it. eg is PERMANENTLY "hello world"

    ps. you do not need to cast malloc in C
    Code:
    char **eg = malloc(sizeof(char*)*10);
    You do not need to malloc **preps at all IF all you are doing is assigning string literals to it's members. However, this makes it a stack (not a heap) variable.
    Last edited by MK27; 11-17-2009 at 12:32 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Registered User
    Join Date
    Apr 2005
    Posts
    13
    I'm going to guess many people here don't bother with double pointers and functions. Neither did I until taking this current class...

    Anyways, it turns out my code is correct except I have to return the double pointer when I allocate the memory for the double pointer otherwise the memory apparently disappears when the function disappears(It's within the scope of the stack, I guess. :/) and creates what my teacher called a "memory leak".

    So, I basically had to put

    return words;

    at the end of the allocation function. I also added a return statement to the other functions, just to be on the safe side.

Popular pages Recent additions subscribe to a feed