1

So i have a program to convert all of the capital letters into smaller ones.

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

char v2m(char z)
{
    if(z >= 'A' && z <= 'Z')
        return z += 32;
    else return z;
}

void convert(char ** array, int n)
{
    for(int i = 0; i < n; i++)
        for(int j = 0; (* (array + i))[j] != '\0'; j++)
            (* (array + i))[j] = v2m((* (array + i))[j]);
}

int main()
{
    char * strings[5] = { "Pen", "Car", "Dev", "Lamp", "Noon" };
    printf("Before: ");
    for(int i = 0; i < 5; i++)
        printf("\n%s", * (strings + i));
    convert(strings, 5);
    printf("\nAfter: ");
    for(int i = 0; i < 5; i++)
        printf("\n%s", * (strings + i));
    return 0;
}

I know that the problem lies in the fact that i can't change the content of pointer arrays and would like to know is there a simpler way that I can declare and initialize array strings without user input. Mainly to modify this part of code.

char * strings[5] = { "Pen", "Car", "Dev", "Lamp", "Noon" };

1 Answers1

2

You're right that you cannot modify the strings in your array, because yours is an array of pointers to string literals, and string literals by definition are constant and cannot be modified, otherwise undefined behavior ensues.

What you can usually do to create your array at compile time while making it modifiable is specify a maximum length for the strings as secondary size:

char strings[5][10] = { "Pen", "Car", "Dev", "Lamp", "Noon" };

This will create an array of 5 arrays of 10 characters each (or, if you will, a 5x10 character matrix), capable of holding strings of up to 9 characters (plus the terminator).

However, if you need your function to take a char ** this won't help, because arrays can only decay into pointers once. If we use the above declaration, we are dealing with an array of arrays, so pointer decay does not apply twice and your function would need to take an char(*)[10] as argument.

To make it work without changing function signature you have two choices:

  1. Create separate arrays and then assign them to an array of pointers to pass:

    char args[5][10] = { "Pen", "Car", "Dev", "Lamp", "Noon" };
    char *strings[5];
    
    for (unsigned i = 0; i < 5; i++)
        strings[i] = args[i];
    
    // ...
    
    convert(strings, 5);
    
  2. Dynamically allocate the strings:

    char *strings[5];
    
    strings[0] = strdup("Pen");
    strings[1] = strdup("Car");
    // ...
    
    convert(strings, 5);
    
    // ...
    
    for (unsigned i = 0; i < 5; i++)
        free(strings[i]);
    

Option 1 seems like the simplest in your case. There are different variations you could use like for example compress it in a single line doing char *strings[5] = {args[1], args[2], ...};.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • I forgot to mention that i am fixed with the declaration of the function convert which expects a type of char ** instead i will send it char (*)[10]. How could i bypass that ? – Edmond Dantes Aug 01 '21 at 01:58
  • @EdmondDantes there is no need to change anything, your function can take a `char **` without a problem. Arrays "decay" into pointers when passed to functions. See: https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay – Marco Bonelli Aug 01 '21 at 02:01
  • Strange, valgrind reports me a warning and a segmentation fault if used like char strings[5][10]. – Edmond Dantes Aug 01 '21 at 02:02
  • 1
    @EdmondDantes ehrm, you're entirely right. Let me edit my answer. – Marco Bonelli Aug 01 '21 at 02:08
  • 1
    @EdmondDantes edited, see if that works for you. – Marco Bonelli Aug 01 '21 at 02:15