简体   繁体   中英

What are the disadvantages of declaring an array of pointers to strings in C?

Is there any negative effect of declaring an array of pointers to string literals if it is not declared as constant?

I'm setting up an array of strings that can be of varying lengths. If I set these up as an array of pointers to string literals, everything seems to work fine, and I can even change them later. I just want to be sure that this is the best approach before I continue with it in a larger scale embedded program.

  • Is there any negative side-effect that this simple example could potentially be missing?
  • Would there be any advantages to declaring it as a 2d array of characters with a max length?

Example:

#include <stdio.h>

char * OutputNames[20] = 
{
    "Output 01",
    "Output 02",
    "Output 03",
    "Output 04",
    "Output 05",
    "Output 06",
    "Output 07",
    "Output 08",
    "Output 09",
    "Output 10",
    "Output 11",
    "Output 12",
    "Output 13",
    "Output 14",
    "Output 15",
    "Output 16",
    "Output 17",
    "Output 18",
    "Output 19",
    "Output 20",
};

char main()
{
    OutputNames[12] = "Test Output";
    for (unsigned char ArrMem = 0; ArrMem < 20; ++ArrMem)
    {
        printf("%s\n", OutputNames[ArrMem]);
    }
    
    getchar();
    return (0);
}

String literals in C are read only (even though their type is actually char [] ), so it would be best to define the array as:

const char * OutputNames[] =
{
   ...
};

Note that this means that what the pointers point to is const , not the pointers themselves. Also, note that the array length is left out so that the size can be dictated by the initializer.

No, this would be my preferred way to store a collection of strings with varying lengths.

The amount of memory required is a little more because you are also storing all the pointers. But if you made a two-dimensional array, you'd waste more memory because each string would need enough room for the longest string.

The main issue with that you need to worry about is freeing up all the memory, but since you're using string constants, that's not an issue here. I would make the array a const .

The main danger is that you might accidentally try to change one of the string literals (possibly deep in some call chain passing the pointers around; tough to debug) causing undefined behavior. Save yourself the headache and declare them as const:

const char *OutputNames[20] = ...

Note that this does NOT declare the ARRAY as const, just the strings pointed to. So you can still change any element of the array (making it point at a different string).

If you actually want to change the strings in run-time, then everything is wrong and you should be using arrays instead.

Is there any negative side-effect that this simple example could potentially be missing?

  • As mentioned, accidentally doing a write access invokes undefined behavior. There is absolutely no reason why you shouldn't declare the pointers as const char* .

  • Since this is an embedded system, the pointer table is incorrectly declared. Not only do you want pointers to read-only data, the pointers themselves should be read-only too, so the array gets allocated in flash rather than RAM. So it must actually be of type const char* const .

This is assuming von Neumann. In case of Harvard architectures you may need to add a few ugly tricks like non-standard keywords.

Would there be any advantages to declaring it as a 2d array of characters with a max length?

This may lead to a lot better performance. First of all, you are guaranteed adjacent allocation. This leads to better performance on systems with data cache support. Since these will be allocated in flash, access is usually slow, with wait states.

Second, you get rid of a whole pointer look-up table which saves memory and potentially gives slightly faster access too, since you drop a level of indirection.

The down-side is that a 2D array is less flexible and you need to allocate fixed lengths.


Not related to your question, char main() is complete hogwash. main() is not some generic function you get to declare as you want, but a specialized one.

  • main() on hosted (PC) systems is int main(void) or optionally with argv + argc.
  • main() on freestanding (embedded) systems is most often the implementation-defined void main(void) since returning from main() is senseless. With gcc-like compiles compile with -ffreestanding .

In either case, it is the compiler who decides the valid forms of main(), never the programmer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM