Thread: Why this (dynamic array) doesn't crash ?

  1. #1
    Registered User
    Join Date
    Jan 2006
    Posts
    13

    Why this (dynamic array) doesn't crash ?

    Hi, i have the following code which manages to get words from a line and store them into an array (number of words is unknown).

    Code:
    char **createArray(char *line, int *length){
      char **array = (char **)malloc(sizeof(char));
      char *word = (char *)malloc(sizeof(char));
      if (word==NULL)
        printf("fail allocating memory");
    
      word = strtok(line, " ");
      int i=0;
      while (word!=NULL){
        array[i] = (char *)malloc(sizeof(char));
        array[i] = word;
        word = strtok(NULL," ");
        i++;
      }
      *length = i;
      return array;
    }

    It works correctly, but im still doubtful if it would ever crash. Specifically, why doesnt it throw a Segmentation error when i call: array[i] = (char *)malloc(sizeof(char)). ???


    im still very new to Pointer this memory allocation concept; so would appreciate any helps.

    Thanks

  2. #2
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    I do not know how this worked correctly

    1) Don't cast malloc's return.
    2) When allocating memory for the char** array, you would allocate not sizeof(char), which is 1 byte, you would allocate memory for a sizeof(char*)
    3) It ends up looking like: malloc(sizeof(char*) * numberOfWordsInTheSentence); You might create a helper function like "int countWordsInSentence(char* line);"
    4) Then you would tokenize the string line, and allocate memory for array[i] = malloc(sizeof(char) * lengthOfTheCurrentTokenizedWordInCharacters);
    5) Then you would strcpy the token into the newly allocated space. You can have the char** array be NULL-terminated so that it does not need a length counter.
    6) You need to free(..) all this memory you are allocating!!

  3. #3
    Registered Luser cwr's Avatar
    Join Date
    Jul 2005
    Location
    Sydney, Australia
    Posts
    869
    It doesn't crash because undefined behaviour can include appearing to work.

  4. #4
    Registered User
    Join Date
    Jan 2006
    Posts
    13
    Quote Originally Posted by cwr
    It doesn't crash because undefined behaviour can include appearing to work.

    Why does the program have undefined behavior ?
    Is there a way to detect this behavior ? I've run the program many time in diferrent machines, with different test file, but didn't find any problem.

    Cheers.

  5. #5
    Registered Luser cwr's Avatar
    Join Date
    Jul 2005
    Location
    Sydney, Australia
    Posts
    869
    Undefined behaviour occurs when an object is referred to when storage is not allocated for it. In the above code, you only allocate space for array to point to one byte (sizeof char is 1 by definition). Therefore, any access to array[i] (even when i is zero) will reach storage that is not allocated (a char * is bigger than one byte).

  6. #6
    Registered User
    Join Date
    Jan 2006
    Posts
    13
    Quote Originally Posted by cwr
    Undefined behaviour occurs when an object is referred to when storage is not allocated for it. In the above code, you only allocate space for array to point to one byte (sizeof char is 1 by definition). Therefore, any access to array[i] (even when i is zero) will reach storage that is not allocated (a char * is bigger than one byte).

    So if i used
    Code:
         char **array = (char *)malloc(sizeof(char*));
    will it fix the problem ? Im still confused about accessing array[i] with any i>0.

  7. #7
    Registered Luser cwr's Avatar
    Join Date
    Jul 2005
    Location
    Sydney, Australia
    Posts
    869
    Did you read Tonto's post? It pointed out that you need to malloc space for another points for each word. You can't just malloc enough for one pointer.

    You are correct that you can't access array[i] where i>0.

    Also, as Tonto said, you should not cast the return of malloc.

  8. #8
    Registered User
    Join Date
    Jan 2006
    Posts
    13
    Quote Originally Posted by Tonto
    I do not know how this worked correctly

    1) Don't cast malloc's return.
    2) When allocating memory for the char** array, you would allocate not sizeof(char), which is 1 byte, you would allocate memory for a sizeof(char*)
    3) It ends up looking like: malloc(sizeof(char*) * numberOfWordsInTheSentence); You might create a helper function like "int countWordsInSentence(char* line);"
    4) Then you would tokenize the string line, and allocate memory for array[i] = malloc(sizeof(char) * lengthOfTheCurrentTokenizedWordInCharacters);
    5) Then you would strcpy the token into the newly allocated space. You can have the char** array be NULL-terminated so that it does not need a length counter.
    6) You need to free(..) all this memory you are allocating!!

    Thank very much for your reply

    1.Why ? I see in many book they recommend to cast
    2. OK, thanks.
    3. Because im using strtok (which does crazy things to the string), its not possible to implement this function and reused the string
    4.
    5.
    6. This array will be used over and over again, so i think deallocating the memory won't work.

  9. #9
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    Okay. array is of type char**. This means it points to several char*'s. These char*'s are C-string's which are pieces of the line you tokenize. You need to make char** array point to enough little slots to hold pieces of the line you are tokenizing. So for example:

    Code:
    int countWords(char* line)
    {
    	int numWords = 0;
    	for(int i = 0; line[i]; i++)
    	{
    		if(line[i] == ' ')
    		{
    			numWords++;
    		}
    	}
    
    	return numWords + 1;
    }
    char **createArray(char *line, int *length)
    {
    	char**	array = malloc(sizeof(char*) * countWords(line) + 1);
    	char*	word = strtok(line, " ");
    
    	int i = 0;
    
    	while (word != NULL)
    	{
    		array[i] = malloc(sizeof(char) * strlen(word) + 1);
    		strcpy(array[i], word);
    
    ... etc ...
    This way, you allocate a char* pointer for each word in the sentence of your char** array, and then you fill up each element of array by allocating enough memory to store each word itself.

  10. #10
    Registered User
    Join Date
    Jan 2006
    Posts
    13
    Quote Originally Posted by cwr
    Did you read Tonto's post? It pointed out that you need to malloc space for another points for each word. You can't just malloc enough for one pointer.

    You are correct that you can't access array[i] where i>0.
    Ok, im still wondering what actually does happen when i call:

    Code:
     array[i] = (char *)malloc(sizeof(char))
    And does "Access array[i]" means getting the content of array[i] or even allocating memory for it ?


    Sorry if the question is silly.

    Your help is very appreciated.

    Cheers

  11. #11
    Registered User
    Join Date
    Jan 2006
    Posts
    13
    Tonto,

    Thanks for reply.
    But it'd be so nice if the string is formatted like that, i.e: words could be seperated by more than one blank characters; so i think it'd be better to use strtok().
    Last edited by soothsayer; 01-26-2006 at 08:01 PM.

  12. #12
    Registered Luser cwr's Avatar
    Join Date
    Jul 2005
    Location
    Sydney, Australia
    Posts
    869
    Quote Originally Posted by soothsayer
    And does "Access array[i]" means getting the content of array[i] or even allocating memory for it ?
    Either, reading or writing. Allocating memory for it is writing a pointer to it.

    And, if your book recommends casting the return of malloc, it's likely a pre-ANSI C book.

    See http://c-faq.com/malloc/cast.html

  13. #13
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    My function was just an example, clearly you would design a more functional robust piece of code for your purposes. If you don't like the solution however, you could realloc. I was just going along with what you already had.

    Code:
    // Just for the jist of it:
    
    char **createArray(char *line, int *length)
    {
    	char**	array = NULL;
    	char*	word = strtok(line, " ");
    
    	int i = 0;
    
    	while (word != NULL)
    	{
    		array = realloc(array, (i * sizeof(char*)) + sizeof(char*));
    		array[i] = malloc(sizeof(char) * strlen(word) + 1);
    
    		strcpy(array[i], word);
    		word = strtok(NULL," ");
    
    		i++;
    	}
    	*length = i;
    	return array;
    }

  14. #14
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Code:
    array = realloc(array, (i * sizeof(char*)) + sizeof(char*));
    array[i] = malloc(sizeof(char) * strlen(word) + 1);
    Not good practice (memory leak on failure).
    By definition 1.
    Error checking would be a good addition. And cleanup a bonus.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. beginner: dynamic array of strings
    By pc2-brazil in forum C++ Programming
    Replies: 10
    Last Post: 04-29-2008, 04:29 PM
  2. Class Template Trouble
    By pliang in forum C++ Programming
    Replies: 4
    Last Post: 04-21-2005, 04:15 AM
  3. Quick question about SIGSEGV
    By Cikotic in forum C Programming
    Replies: 30
    Last Post: 07-01-2004, 07:48 PM
  4. 2D dynamic array problem
    By scsullivan in forum C Programming
    Replies: 3
    Last Post: 12-30-2002, 10:02 PM
  5. Dynamic array allocation and reallocation
    By purple in forum C Programming
    Replies: 13
    Last Post: 08-01-2002, 11:48 AM