Introduction #
In embedded C, double pointers (char **
) can be confusing, especially when combined with arrays. Different memory models behave differently, and understanding them is key to writing safe and efficient code.
We’ll go through three common memory models with examples, printing functions, and a practical sorting case.
1. Pointer Array (char *arr[]
)
#
// Define an array of pointers to strings
char *arr[] = {"abc", "def", "ghi"};
This creates an array where each element stores the address of a string literal.
Intermediate variable:
char *tmp = NULL; // pointer to a string
Print function:
int printArray(char **srcArray, int count)
{
if (srcArray == NULL) return -1;
for (int i = 0; i < count; i++) {
printf("%s\n", srcArray[i]); // print each string
}
return 0;
}
2. Two-Dimensional Array (char arr[][]
)
#
// Define a 2D character array
char arr[3][5] = {"abc", "def", "ghi"};
This allocates 3 rows × 5 characters in contiguous memory.
Intermediate variable:
char tmp[5] = {0}; // buffer for a single row
Print function:
int printArray2D(char srcArray[][5], int count)
{
if (srcArray == NULL) return -1;
for (int i = 0; i < count; i++) {
printf("%s\n", srcArray[i]);
}
return 0;
}
3. Dynamic Double Pointer (char **arr
)
#
// Allocate memory for 100 string pointers
char **arr = (char **)malloc(100 * sizeof(char *));
// Allocate memory for each string
arr[0] = (char *)malloc(100 * sizeof(char));
arr[1] = (char *)malloc(100 * sizeof(char));
arr[2] = (char *)malloc(100 * sizeof(char));
// Copy strings into allocated memory
strcpy(arr[0], "abc");
strcpy(arr[1], "def");
strcpy(arr[2], "ghi");
Free memory:
for (int i = 0; i < 3; i++) {
if (arr[i] != NULL)
free(arr[i]); // free each string
}
free(arr); // free the pointer array itself
Intermediate variable:
char *tmp = NULL; // temporary string pointer
Example: Sorting Strings with Double Pointers #
// Copy strings from srcArray into new memory, then sort
char **sortArrayAndAlloc(const char **srcArray, int count, char *extra, int *outCount)
{
// Allocate array of pointers
char **outArray = (char **)malloc(count * sizeof(char *));
if (srcArray == NULL || extra == NULL || outCount == NULL) {
printf("Invalid parameters\n");
return NULL;
}
*outCount = count;
for (int i = 0; i < count; i++) {
outArray[i] = (char *)malloc(50 * sizeof(char)); // allocate space for each string
memset(outArray[i], 0, 50);
strcpy(outArray[i], srcArray[i]); // copy string
}
// Simple bubble sort by string comparison
for (int i = 0; i < count; i++) {
for (int j = i + 1; j < count; j++) {
if (strcmp(outArray[i], outArray[j]) > 0) {
char *tmp = outArray[i];
outArray[i] = outArray[j];
outArray[j] = tmp;
}
}
}
return outArray;
}
Usage:
int main()
{
char *srcArray[] = {"bbbbb", "aaaaa", "cccccc"};
char *extra = "111111111111"; // unused in this example
int outCount = 0;
// Get sorted array
char **sortedArray = sortArrayAndAlloc(srcArray, 3, extra, &outCount);
// Print and free
for (int i = 0; i < outCount; i++) {
printf("%s\n", sortedArray[i]);
free(sortedArray[i]); // free each string
}
free(sortedArray); // free pointer array
return 0;
}
Utility Functions #
// Allocate memory for an array of strings
int allocArray(char ***outArray, int count)
{
char **tmp = (char **)malloc(count * sizeof(char *));
for (int i = 0; i < count; i++) {
tmp[i] = (char *)malloc(100 * sizeof(char)); // each string can hold 100 chars
}
*outArray = tmp;
return 0;
}
// Free memory for an array of strings
int freeArray(char ***outArray, int count)
{
char **p = *outArray;
for (int i = 0; i < count; i++) {
free(p[i]);
}
free(p);
*outArray = NULL;
return 0;
}
Summary #
- Pointer array (
char *arr[]
) → array of string pointers. - 2D array (
char arr[][]
) → fixed-size, contiguous memory. - Dynamic double pointer (
char **arr
) → flexible, requires manual memory management.