0

I am trying to understand what is wrong with my code and my understanding of pointers, arrays and string in C.

I tried to create an array of strings, to be able to loop over it and to test any functions that take a string as a parameter. In this case, i'm trying to check my private implantation of memset called Memset.

This is my code:

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

/*First Try, did not work: */

/*const char * strings_array[] = {*/
/*    "First string",*/
/*    "213123Second_string3",*/
/*    "",*/
/*    "-3",*/
/*    "s",*/
/*};*/

/* Second try, also does not work: */

const char **strings_array = (char *[]){"a", "b", "c"};

int main () 
{

    while(*strings_array)
    {
    char *string = strings_array;
    printf( "Before Memset, target is \"%s\"\n", *string );
    if (NULL == Memset(*string, '$', 4))
    {
        fprintf(stderr,"Memset failed!\n");
    }
    printf( "After Memset, target is \"%s\"\n\n", *string );
    
    ++strings_array;
    }
return (0);
}

I know that a string in C is not a type but a char *. But it is also a string literal, which means I can't change it, and can only read it.

That's why it's not working? Because I'm passing it to Memset and Memset tries to change it while it can not be changed because it's a string literal?

This is my implantation of my Memset function:

void *Memset(void *str, int c, size_t n)
{
        unsigned char *string = str;
        
        if (NULL == str)
        {
            return (NULL);
        }
        
        while(n > 0)
        {
            *string++ = (unsigned char) c;
            --n;
        }

    return (str);
}
NoobCoder
  • 513
  • 3
  • 18
  • 2
    As you say: you can't apply `memset` to a string literal. One way around is to use a 2D array instead of an array of pointers. Or if you must use an array of pointers, allocate memory for and copy the data, such as with `strdup()`. – Weather Vane Mar 08 '21 at 14:48
  • `char *string = strings_array;` should be `char *string = *strings_array;`, it should also be noted that this is an infinite loop, for it to stop you need to null terminate `strings_array` –  Mar 08 '21 at 14:50
  • @WeatherVane But we do pass `string literals` to functions like `memset`.. I mean I can write `char str[50]` and `strcpy(str,"This is a Memset test")` and send `str` to `memset` and it will work. So why can't it be the same with array of string that generate the same thing as `str` in my example above. – NoobCoder Mar 08 '21 at 14:54
  • But `str[50]` is not a string literal. `"This is a Memset test"` is the string literal, which is copied into the array. That does not make the array a string literal, and `memset` will behave the same whether or not you previously copied data into the array. – Weather Vane Mar 08 '21 at 14:57
  • @WeatherVane Got ya. So if i'll crate a 2D array like people mentioned here in the comments, I'll basically will create lots of strings as `str[50]` for example? – NoobCoder Mar 08 '21 at 14:59
  • In the answer from dbush the strings can be accessed as `strings_array[0]` thru `strings_array[4]`. – Weather Vane Mar 08 '21 at 15:02
  • so in the end, there is no way to me to access, change or pass and work with structs array as pointers? I can't do pointer arithmetic as I wanted to do. – NoobCoder Mar 08 '21 at 15:05
  • arrays aren't pointers, you can't increment a an array, you need to use a pointer to iterate through it. –  Mar 08 '21 at 15:06
  • Please study the two linked duplicates. This has been answered many times before. The TL;DR is that `char str[50] = "foo";` makes a copy of the string literal and the array str is in read/write memory. – Lundin Mar 08 '21 at 15:06
  • Of course you can. If you pass `strings_array[4]` to a function, it decays to a pointer. – Weather Vane Mar 08 '21 at 15:06
  • @Lundin I know. I did write it in my post. I'm asking here something else about passing it as an array to a function that accepts `strings`. I personally don't think it's a duplicated question. – NoobCoder Mar 08 '21 at 15:07
  • 1
    As you say yourself, you can't pass it to such a function, because the pointers are pointing at string literals. You've essentially answered the question yourself. – Lundin Mar 08 '21 at 15:31

2 Answers2

2

Your assesment is correct. You're creating an array of char * and initializing those pointers the the address of string constants, and string constants cannot be modified.

Instead of defining an array of char *, define a 2D array of char. While you use string constants to initialize the array, the array itself it writable.

char strings_array[][50] = {
    "First string",
    "213123Second_string3",
    "",
    "-3",
    "s",
};

Note that for a multidimensional array, only the first dimension can have the size omitted if there is an initializer.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

The first mistake that popped out at me was that in Memset you indirectly cast a void* to unsigned char *. I would change this to an explicit cast: unsigned char *string = (unsigned char *)str;

Secondly, you are absolutely correct: string literals cannot be modified. An attempt to modify a string literal would result in an error.

To test this code, I would try to allocate a string array on the heap, load some test strings into there, and then pass your string pointers from that array into your Memset function.

JJ Cheng
  • 51
  • 4