cpointersdynamic-memory-allocationc-stringsdouble-pointer

When Declaring a Double Pointer that is an array why is there no need to put brackets because it is an array of pointers?


    #include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** AllocateShoppingList(int numFoods);
char* AllocateItem();
int DetermineNumberOfCandy(char** list, int numFoods);

int main()
{
  
   char** stringArray;// pointer to pointers
   char* words; //pointer to char array
   //1. ask the user how many foods are on their list
   int foods;
   printf("How many foods on the shopping list?\n");
   scanf("%d", &foods);
   //2. call the AllocateShoppingList function and store the result
   stringArray = AllocateShoppingList(foods);   
   //3. for X times (user's previous input), call the AllocateItem function 
   //       and store the result in the list of pointers (step 2)
   for(int i =0;i < foods; i++){
   words = AllocateItem();
   stringArray[i] = words;}

  //strcpy(stringArray[i],words); why not work?
   
   //4. call the DetermineNumberOfCandy function, and print the result
   printf("Candy appeared this many times: %d\n",DetermineNumberOfCandy(stringArray, foods)); 
   //5. free up all of the pointers that are held by the shopping list
   //6. free up the shopping pointer itself
   free(words);
   free(stringArray);
   
}

int DetermineNumberOfCandy(char** list, int numFoods)
{
   //0. setup a counter variable
   int counter = 0 ;
   //1. for each pointer in the shopping list:
   //1a.   compare the string at the pointer's address to "candy"
   
   for(int i =0; i< numFoods; i++)
   if (strcmp(list[i],"candy")==0)
     // why you dont have to dereference it
     // this concept works with single pointers
     // does it work with double or tripple pointers as long as it orignally points to the string?
     
   counter++;
   
   //1b.   if it is candy, then tick up the counter variable
   //2. return the counter variable
   return counter;
}

char** AllocateShoppingList(int numFoods)
{
   
   return calloc(numFoods, sizeof(char*));
   //1. allocate memory that can hold X pointers (X = numFoods)
   //2. return the memory address holding this pointer to pointers
}

char* AllocateItem()
{
   char* wordPtr;
   char word[100];
   //1. get a word from the user that is max 100 characters
 
   scanf("%s", word);
   //2. determine how large the word actually is
   wordPtr = calloc(strlen(word)+1,sizeof(char));
   strcpy(wordPtr, word);
   //3. allocate memory that is just enough to hold the word
   return wordPtr;
   //4. copy the user's word into the new memory location
   //5. return the memory address holding the word
}

**For this code we had to get a shopping last and see print out how many times candy was in the shopping list and in order to do that we had to allocates enough memory to hold onto as many words (strings) as the user wants to have on their shopping list. Then, for each item, allocate just enough memory to store the word. **

This declaration right here for me doesn't make sense

**char** stringArray; **

From what I understand the double pointer is an array which element in the array contains a pointer to the string address.

Because of this I would think that we would have to declare the double pointer like:

char stringArray[]; **

something like this but that would not work.

So I wanted to know how the code knows it is an Array of pointers if we never put brackets

I tried declaring the double pointer with an array and could not get it to work nor could figure out if it was even possible.


Solution

  • Pointers are pointers, arrays are arrays. However, when an array in C is used in an expression or passed as a parameter to a function, it "decays" into a pointer to the first element of that array. This in turn enables things like a pointer arithmetic and the convenient use of the [] index operator.

    This also means that in most contexts, a pointer to the first element can be used in place of an array. If we have an array of pointers char* arr[n]; then a char** can be used to point at the first item, and from there on the rest of the array.

    So if you'd write a function like int DetermineNumberOfCandy(int numFoods, char* list[numFoods]); that's fine and valid C, but list "decays" into a pointer to the first element anyway, so it is 100% equivalent to
    int DetermineNumberOfCandy(int numFoods, char** list);


    Also you have misc bugs in your code.