-1

When we allocating memory spaces for a string, do the following 2 ways give the same result?

char *s = "abc";
char *st1 = (char *)malloc(sizeof(char)*strlen(s));
char *st2 = (char *)malloc(sizeof(s));

In other words, does allocate the memory based on the size of its characters give the same result as allocating based on the size of the whole string?

If I do use the later method, is it still possible for me to add to that memory spaces character by character such as:

*st = 'a';
st++;
*st = 'b';

or do I have to add a whole string at once now?

Claire
  • 167
  • 4
  • No. `sizeof(s)` is sizeof `a_pointer`, `strlen(s)` will be the number of characters in the string literal (`3`). You can iteratre over the generic pointer `st` as you have shown. You just keep track of the number of characters used and `realloc()` when you run out. – David C. Rankin May 01 '21 at 01:41
  • 1
    you should print out the values of the sizeof – Daniel A. White May 01 '21 at 01:42
  • `sizeof(s)` is the size of a pointer, not the size of a string. – MikeCAT May 01 '21 at 01:43
  • Also don't forget to allocate for terminating null-character when you allocate for strings. – MikeCAT May 01 '21 at 01:44

1 Answers1

1

Let's see if we can't get you straightened out on your question and on allocating (and reallocating) storage. To begin, when you declare:

char *s = "abc";

You have declared a pointer to char s and you have assigned the starting address for the String Literal "abc" to the pointer s. Whenever you attempt to use sizeof() on a_pointer, you get sizeof(a_pointer) which is typically 8-bytes on x86_64 (or 4-bytes on x86, etc..)

If you take sizeof("abc"); you are taking the size of a character array with size 4 (e.g. {'a', 'b', 'c', '\0'}), because a string literal is an array of char initialized to hold the string "abc" (including the nul-terminating character). Also note, that on virtually all systems, a string literal is created in read-only memory and cannot be modified, it is immutable.

If you want to allocate storage to hold a copy of the string "abc", you must allocate strlen("abc") + 1 characters (the +1 for the nul-terminating character '\0' -- which is simply ASCII 0, see ASCII Table & Description.

Whenever you allocate memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. So if you allocate for char *st = malloc (len + 1); characters, you do not want to iterate with the pointer st (e.g. no st++). Instead, declare a second pointer, char *p = st; and you are free to iterate with p.

Also, in C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.

If you want to add to an allocation, you use realloc() which will create a new block of memory for you and copy your existing block to it. When using realloc(), you always reallocate using a temporary pointer (e.g. don't st = realloc (st, new_size);) because if when realloc() fails, it returns NULL and if you assign that to your pointer st, you have just lost the original pointer and created a memory leak. Instead, use a temporary pointer, e.g. void *tmp = realloc (st, new_size); then validate realloc() succeeds before assigning st = tmp;

Now, reading between the lines that is where you are going with your example, the following shows how that can be done, keeping track of the amount of memory allocated and the amount of memory used. Then when used == allocated, you reallocate more memory (and remembering to ensure you have +1 bytes available for the nul-terminating character.

A short example would be:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define THISMANY 23

int main (void) {

    char *s = "abc", *st, *p;               /* string literal and pointer st */
    size_t  len = strlen(s),                /* length of s */
            allocated = len + 1,            /* number of bytes in new block allocated */
            used = 0;                       /* number of bytes in new block used */
    
    st = malloc (allocated);                /* allocate storage for copy of s */
    p = st;                                 /* pointer to allocate, preserve st */
    
    if (!st) {                              /* validate EVERY allocation */
        perror ("malloc-st");
        return 1;
    }
    
    for (int i = 0; s[i]; i++) {            /* copy s to new block of memory */
        *p++ = s[i];                        /* (could use strcpy) */
        used++;                             /* advance counter */
    }
    *p = 0;                                 /* nul-terminate copy */
    
    for (size_t i = 0; i < THISMANY; i++) { /* loop THISMANY times */
        if (used + 1 == allocated) {        /* check if realloc needed (remember '\0') */
            /* always realloc using temporary pointer */
            void *tmp = realloc (st, 2 * allocated);    /* realloc 2X current */
            if (!tmp) {                     /* validate EVERY reallocation */
                perror ("realloc-st");
                break;                      /* don't exit, original st stil valid */
            }
            st = tmp;                       /* assign reallocated block to st */
            allocated *= 2;                 /* update allocated amount */
        }
        *p++ = 'a' + used++;                /* assign new char, increment used */
    }
    *p = 0;                                 /* nul-terminate */
    
    printf ("result st  : %s\n"             /* output final string, length, allocated */
            "length st  : %zu bytes\n"
            "final size : %zu bytes\n", st, strlen(st), allocated);
    
    free (st);      /* don't forget to free what you have allocated */
}

Example Use/Output

$ ./bin/sizeofs
result st  : abcdefghijklmnopqrstuvwxyz
length st  : 26 bytes
final size : 32 bytes

Look things over and let me know if this answered your questions, and if not, leave a comment and I'm happy to help further.

If you are still shaky on what a pointer is, and would like more information, here are a few links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85