3

First of all, this is a test program, i wanna test something specific that i wanted to see if it works. Lets say that i wanna assign x to arr[0][4] and wanna keep this change so that arr[0][4] is x in the main function too:

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

void changE(char *arr[10][5]);

int main(void){
    char *arr[10][5];
    arr[0][0] = "Johny";
    arr[0][1] = "Tony";
    arr[0][2] = "Tiki";
    arr[0][3] = "Kitty";
    arr[0][4] = "Douglas";
    arr[1][0] = "Piki";
    arr[1][1] = "Kati";
    arr[1][2] = "Sathi";
    arr[1][3] = "Dony";
    changE(arr);
    int i = 0;
    int j;
    for(i;i<=1;i++){
        for(j=0;j<=4;j++){
            printf("%s\n", arr[i][j]);
        }
        printf("\n\n\n");
    }
    return 0;
}
void changE(char *arr[10][5]){
    char x[50] = "Tinky";
    arr[0][4] = x;
}

The problem is that i cant assign x to arr[0][4], the program just shuts down. I also tried strcpy, this:

void changE(char *arr[10][5]){

    char x[50] = "Tinky";
    strcpy(arr[0][4], x);
}

Its the same thing with strcpy the program just shuts down. I can only do this:

void changE(char *arr[10][5]){
    arr[0][4] = "Tinky";
}

Which doesnt help me at all, considering that x is a string that i dont know(or a string from scanf). So if x comes from a scanf how can i assign x to arr[0][4]? Any help would be appreciated! Thanks :)

2
  • 1
    C does not nave a string type. Whether a sequence of char is a "string" is just convention of the functions used. Please read about pointers and arrays in C. Commented Jan 2, 2016 at 22:05
  • this line: for(i;i<=1;i++){ has a logic error. Your compiler should have told you about this problem. Suggest either: for(i=0; i<=1; i++){ or for(; i<=1; i++){ Commented Jan 4, 2016 at 6:32

6 Answers 6

4

This method

void changE(char *arr[10][5]){
    char x[50] = "Tinky";
    arr[0][4] = x;
}

doesn't work because you are assigning a variable with automatic storage (aka "local") duration. Once the function returns, it doesn't exist anymore. This is undefined behaviour.

This method

void changE(char *arr[10][5]){

    char x[50] = "Tinky";
    strcpy(arr[0][4], x);
}

doesn't work because the arr[0][4] is pointing to a string literal. You can't modify a string literal. Again, this is undefined behaviour.

This method

void changE(char *arr[10][5]){
    arr[0][4] = "Tinky";
}

is the only correct way if you only have pointers and not allocated any memory for the pointees of those pointers.

So if x comes from a scanf how can i assign x to arr[0][4]?

For such scenario, you need to allocate memory and assign it to arr[0][4].

void changE(char *arr[10][5]){ 
   char x[40] = "Tinky";
   arr[0][4] = strdup(x); //POSIX, equivalent std C would be malloc()+strcpy()
}

This is quite messy though. The array has pointers to string literals. But just arr[0][4] is pointing to a malloc'ed memory. You need to track such pointers if you want to be able to modify it or later when you call free() on it.

I would suggest you use just arrays instead of arrays of pointers if you want to be able to modify them as it's hard to keep track various pointers that are malloc'ed and with rest of them pointing at string literals.

Sign up to request clarification or add additional context in comments.

5 Comments

You can't modify a string literal but can modify a pointer pointing to string literal.
@haccks It is at strcpy(arr[0][4], x);
So is there a way to create just a 2 dimensional array of strings? Because i search on how to create array of string and all i find is that pointers do the trick.
@MartinZabel; I think I mixed up two answers here, your's and Weather Vane. Deleted my comments. Sorry for that.
@OnceUaT Look at the answer from Vlad, maybe this is what you are asking for
1

At first, you should initialize your array arr, so that, it contains no invalid pointers:

char *arr[10][5] = {0};

Your first implementation of changE does not work because char x[50] is a local variable (allocated on the stack) initialized to "Tinky". You cannot excess this variable (by derefencing the pointer) once the function returns.

The implementation using strcpy does not work, because the destination memory is the string literal "Douglas" (as assigned in main) which cannot be overriden.

The pointer assignment from the first implementation is just fine, but you have to allocate memory from the heap as in this scanf example:

void changE(char *arr[10][5]){
    char *x = (char *)malloc(100 * sizeof *x);
    if(!x) exit(1); // error handling
    scanf("%99s", x);
    arr[0][4] = x;
}

Comments

1

String literals have static storage duration. So these assignments

arr[0][0] = "Johny";
arr[0][1] = "Tony";
arr[0][2] = "Tiki";
arr[0][3] = "Kitty";
arr[0][4] = "Douglas";
arr[1][0] = "Piki";
arr[1][1] = "Kati";
arr[1][2] = "Sathi";
arr[1][3] = "Dony";

or this assignment in function changE

arr[0][4] = "Tinky";

are coorect.

However you want to assign an element of the array with address of some character array that you are going to enter. In this case the storage duration of the array should be at least the same as the storage duration of the two-dimensional array.

The only reasonable approach is to dynamically allocate memory for readable characters and store their addresses in elements of the two-dimensional array.

You could use POSIX function strdup to do this. For example

arr[0][0] = strdup( "Johny" );
arr[0][1] = strdup( "Tony" );
arr[0][2] = strdup( "Tiki" );
arr[0][3] = strdup( "Kitty" );
arr[0][4] = strdup( "Douglas" );
arr[1][0] = strdup( "Piki" );
arr[1][1] = strdup( "Kati" );
arr[1][2] = strdup( "Sathi" );
arr[1][3] = strdup( "Dony" );

Or you could write such a function yourself.

In this case you have to use also standard C function free to free all allocated memory by strdup or similar function.

The same approach should be used in the function changE

For example

void changE(char *arr[10][5]){
    char x[50] = "Tinky";
    arr[0][4] = malloc( strlen( x ) + 1 );
    strcpy(arr[0][4], x);
}

2 Comments

I was going to suggest the strdup approach myself. But, now, changE should do free(arr[0][4]) before reassigning it. Actually, realloc may work as well. If you clean a bit, I'll be glad to upvote.
And, you should maybe use a scanf example within changE.
1

In the first function example that fails, you are trying to copy an automatic string variable to a string literal, which is read-only. That's why the function fails. arr[0][4] is a pointer to a string literal.

void changE(char *arr[10][5]){
    char x[50] = "Tinky";
    strcpy(arr[0][4], x);
}

But in the second example that succeeds, you assign a string literal pointer directly (as you did in the first initialisation).

void changE(char *arr[10][5]){
    arr[0][4] = "Tinky";
}

As an aside, note the difference between

char name[] = "Alex";

and

char *name = "Alex";

In the first case, name is initialised with a copy of the data given, and it is modifiable.

In the second case, all name knows is a pointer, and the text it points to (a "string literal") is not modifiable.

9 Comments

Thanks for answering! I think i did understand what you said. So is there a way to achieve what i need(x to arr[0][4] without assign the string directly). Maybe make x global pointer or something?
In the first function example that fails, you are trying to copy a dynamic string to a string literal, which is read-only. No that's not the case.
You would need to allocate memory with malloc to the string pointer array elements first (allowing for string terminators!) Then copy the string literals, instead of assinging their pointers to the array. When you need a different string there, it might be a different size, so you would realloc the memory for that array element.
@haccks slight tweak thanks of "dynamic string" to "automatic string variable". the other part is true, despite your comments under another answer.
I think haccks is confused because you both numbered the implementations differently. For haccks, the implementation using strcpy is the second one because the first one as actually in the first code block of the question (see his post).
|
1

All the elements of arr are pointers to char. You initialized them in main, no memory is allocated. They just point to string literals.

The first version of changeE

void changE(char *arr[10][5]){
    char x[50] = "Tinky";
    arr[0][4] = x;
} 

doesn't work because x is an automatic local variable and returning pointer to it leads to undefined behavior.

In function

void changE(char *arr[10][5]){

    char x[50] = "Tinky";
    strcpy(arr[0][4], x);
}

strcpy wouldn't work because arr[0][4] is pointing to a string literal and it can't be modified. You can modify arr[0][4] by allocating space for it

void changE(char *arr[10][5]){

    char x[50] = "Tinky";
    arr[0][4] = malloc(strlen(x) + 1);
    strcpy(arr[0][4], x);
}   

Comments

0

A possible solution is to have character arrays instead of pointers to characters like below. The strings' maximum length is 50 in this example.

void changE(char arr[10][5][50]);

int main(void){

    char arr[10][5][50];

    //...

    strcpy(arr[0][0], "Johny");
    strcpy(arr[0][1], "Tony");

    //...
    changE(arr);
    //...
}
void changE(char arr[10][5][50]){
    //this works now
    char x[50] = "Tinky";
    strcpy(arr[0][4], x);

    //scanf works as usual
    scanf("%s", &arr[0][4]);
}

2 Comments

You should explicitly mention that the maximum string length is now 50. And you should respect this the scanf call.
Ups, at first, I have to correct me, the maximum string length is 49 because of the terminating NUL character. So if someone enters 50 character at the scanf prompt, then the terminating NUL character will be written at arr[0][4][50] which is beyond the limits of arr[0][4], so that, the NUL character is actually placed at arr[1][0][0]. Thus, you must define the maximum string length in the call with scanf("%49s"), for example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.