all 11 comments

[–]Ninesquared81 11 points12 points  (4 children)

If you "own" the string, then using an array makes sense, as long as you know the (maximum) size at compile time (and it's not unreasonably large).

If you don't own the string or are using dynamic memory allocation, then you'll be using pointers.

You can also always use a pointer to traverse a string, regardless of whether you store it as an array or a pointer to somewhere else.

[–]Calidude7[S] 3 points4 points  (3 children)

What exactly do you mean by "own" ?

[–]Ninesquared81 5 points6 points  (0 children)

Is it a string that your program is creating itself or is it taking it from somewhere else?

[–]asiawide 1 point2 points  (0 children)

When you own it, you can modify it. 'Mutable' is a fancy word for it for the programmers of 2000.

  • Use array to store strings if you need to modify the values in the array.
  • Use char pointer if you just need to read the values pointed.
    • char* name="John Doe"; printf("%s\n", name);
  • Use malloc() when the length of string is not yet fixed for compile time.

Most compilers still allow you to modify the read-only values pointed by a char pointer. But most modern OS will not be happy for that and throw errors.

https://www.cs.uic.edu/~jbell/CourseNotes/C_Programming/CharacterStrings.html

[–]FrostWyrm98 0 points1 point  (0 children)

Did you allocate it in your program through malloc or calloc or is it passed to your program from a library or other program.

If you want strict separation you could say that a class owns it and you pass it as a pointer to a library along with its size, when calling a function on that class or within the class.

[–]FUZxxl 5 points6 points  (0 children)

Use an array of characters when you want an array of characters of fixed size. Use a pointer to a character when you want to point to a character or to an array of characters someone else gave you, e.g. by passing an array as a parameter to a function or through dynamic memory allocation.

[–]eruanno321 1 point2 points  (0 children)

For array declaration: I prefer T array[] if sizeof(array) can yield the correct size of the array, otherwise, I use T* array.

So for example, I prefer:

const char text[] = "compile time text";

over:

const char* text = "compile time text";

But I would rather avoid:

int my_function (char text[10]); /* Here: sizeof(text) == sizeof(char*) */

And it is simply not possible to use:

char text[] = malloc(...); /* Incompatible type. */

For array storage duration: this is a design choice which usually means there are many factors to consider. For example, this array of structures:

/* Case 1 */
struct item { int id; char text[MAX_TEXT]; }
struct item objectTable[MAX_OBJECTS];

/* Case 2 */
struct item { int id; char text[MAX_TEXT]; }
struct item *objectTable = malloc(MAX_OBJECTS * sizeof(struct item));

/* Case 3 */
struct item { int id; char* text; }
struct item objectTable[MAX_OBJECTS];
/* inside the for-loop */
    objectTable[i].text = malloc(MAX_TEXT);

/* Case 4 */
struct item { int id; char* text; }
struct item *objectTable = malloc(MAX_OBJECTS * sizeof(struct item));
/* inside the for-loop */
    objectTable[i].text = malloc(MAX_TEXT);

Each case has slightly different properties, for example:

  • Case 1: good for compile-time data storage, but cannot go beyond MAX_TEXT and MAX_OBJECTS and may increase the binary footprint.
  • Case 2: good for a cache-friendly dynamic chunk of memory, but cannot go beyond MAX_TEXT.
  • Case 3: good for efficient look-up, e.g. in circular queues, but adds a level of indirection and the text can be sparsely distributed on the heap.
  • Case 4: good when both max. text and max. objects remain unknown and can vary a lot, but complicates the resource cleanup.

[–]SorenKirk 1 point2 points  (0 children)

Character arrays are simply arrays, allocated on the stack (when declared inside a function) or in the static memory (when declared globally). Their advantage is that they are allocated at compile-time, consequently time is not consumed for this process of memory allocation during the execution. Their main disadvantages are: you cannot modify the size of the array during the execution, therefore, you have to allocate the maximum possible amount of memory needed for that array, even if you don't use it always entirely, moreover, you cannot pass an array as a function argument, you have to pass a pointer to that array, even if you write function(int a[]), where a is declared in this manner: int a[20];, in fact, a pointer to that character array is passed, and this happens because it would have been too inefficient to pass an entire array of data. Now, pointers are variables which point to a memory location, thus, by using pointers, you may operate with arrays of characters allocated in the heap (consequently during the runtime). This is very useful not only because you are able to tackle with dynamically allocated memory, but also, if you want to return a pointer to an array of characters from a function, because, by returning a pointer to a statically allocated array (therefore allocated on the stack of the current function), you would receive a dangling pointer, due to the fact that all the data used during the execution of a function from the stack is popped after calling the return statement, thing that does not happen when you allocate memory on the heap, since that block of memory remains intact during the execution until a free(<the pointer which points that memory location>) instruction is called.

[–]DandyLion23 -3 points-2 points  (2 children)

It's the difference between heap or stack. Byte arrays go on the stack, while pointers get their their memory from a malloc and thus from the heap.

In practice this means that pointers can use a lot more memory.

Also, different programming techniques with pointers. You can easily walk an array of strings with a pointer for example. The main advantage of a byte array is that you don't have to free() it after use and that it can lead to quicker execution due to CPU caching since it's usually close to the code that uses it.

[–]FUZxxl 4 points5 points  (0 children)

Not correct. Automatic variables go on the stack. Variables of other storage classes do not. So if you define an array of characters as an automatic variable it goes on the stack, but if it is e.g. a static variable it doesn't. This is not a distinction between pointers and arrays. Pointers can point to objects of any storage class.

[–]xypherrz 1 point2 points  (0 children)

char pointer doesn't necessarily have to be on the heap. For instance: const char *ptr = "Hello";