简体   繁体   中英

How to modify individual characters in an array of strings in C?

I have an array of type char** and I need to modify individual characters in its strings. It gives me a segmentation fault. A minimal sample of that:

  char *a[1] = { "Test" };
  printf("%c\n", a[0][2]); //Output:  's'
  a[0][2] = 'e';  //Segfault here
  printf("%c\n", a[0][2]);

I understand that declaring a string as a character array rather than a char pointer gives the ability to change individual characters, like this:

char c[] = "Str";
c[1] = 'r';
printf("%s\n", c);

But I am not clear on how I can make the latter technique work in the former context, or at least, how to be able to change individual characters in strings which are contained within arrays, whatever the means.

If you were looking for alternative,this can be one

char *a[2];
a[0]= strdup("Test");
a[1]= strdup("Thisworked");
...
a[0][2]='e'; // works.
...
free(a[0]);
free(a[1]);

You can duplicate the string so that you can edit it. Trying to modify it is undefined behavior. In your case that undefined behavior leads to segmentation fault. From standard §6.4.5¶7

It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined .

And again, you can do the same thing like you did - you can initialize a char array with the literal strings - it is modifiable because a copy of the string is being created. (which has no constraint of non-modifiability like string literals). Also if you know that all the literals that you want to use has MAXLETTER number of characters then you can do this

#defined MAXLETTER 20
char c[][MAXLETTER+1]={"Test","Helloworld!"};

Standard mentions it §6.7.9¶14

An array of character type may be initialized by a character string literal or UTF-8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array .

With

char *a[1] = { "Test" };

you declare that a is an array of a single pointer to char , ie it could be seen as an array of strings. And you make the pointer point to the literal string "Test" . The problem is that literal strings are read only .

Literal strings might not be constant, but they can still not be modified. Attempting to do so will lead to undefined behavior .

With

char c[] = "Str";

you have an array of four characters. It's not constant, and not read-only. You can modify it to your hearts content (as long as you stay withing the bounds of the array, and don't modify the string terminator to be something else).

case 1 :

 char *a[1] = { "Test" };

In the above statement a is an array of char pointer , it looks like

  ------------------------
  |  t | e  | s | t | \0 |   <------code or read only section of RAM, u can't modify the content
  ------------------------ 
    |                   0x500
 ----------
|   0x500  |
 -----------
           a  <---- stack section 

In this case a[0][2] = 'e'; is not possible because you try to change the read only section of RAM. you can do a[0] = "hello" because then you are changing the address which is possible.

Case 2 :

char c[] = "Str";

In the above statement c is am char array and its content are stored in stack section of the RAM and you can modify its content that means c[1] = 'r'; is possible.

your question is how to modify it, its not possible with char*a[1] , Instead of char*a[1] you can use char a[1][10] then it's possible, this is one solution.

Your other option, aside from the standard declaration of a as any array of chars is to use a compound literal to initialize your pointer as a pointer to an array as opposed to a pointer to string-literal . C99 introduced the compound literal that allows you to initialize a pointer to a specified type. It has the general form of a cast followed by an initializer. In your case, you would initialize your single pointer within your array of pointers as,

char *a[1] = { (char[]){"Test"} };

The compound-literal being:

(char[]){"Test"}      /* which is the literal "Test" initialized as an array */

This initializes the pointer element a[0] as a pointer to array instead of pointer to string-literal . Your code would then look like:

#include <stdio.h>

int main (void) {
    char *a[1] = { (char[]){"Test"} };
    printf("%c\n", a[0][2]);            /* output 's' */
    a[0][2] = 'e';                      /* no Segfault here */
    printf("%c\n", a[0][2]);            /* output 'e' */
    return 0;
}

Example Use/Output

$ ./bin/cmplitptp
s
e

As noted in several cases, your choice of declaring a as an array of pointers to char with one-element , is a bit out of the ordinary. Generally speaking if you wanted to initialize an array of characters, you would simply declare char a[] = "Test"; . However, you can also declare a as a simple pointer to char and use a compound literal to initialize that pointer as a pointer to array, eg char *a = (char[]){ "Test" }; , which would eliminate one-level of indirection on a simplifying your code to:

#include <stdio.h>

int main (void) {
    char *a = (char[]){ "Test" };
    printf("%c\n", a[2]);               /* output 's' */
    a[2] = 'e';                         /* no Segfault here */
    printf("%c\n", a[2]);               /* output 'e' */
    return 0;
}

(same output)

While it practice you will generally see a compound literal used to initialize a struct , there is no reason they cannot be used to initialize an array. Add it to your C-toolbox, and, in practice, if you want a as an array initialized to a specific string, just use char a[] = "Some String"; .

regarding:

char *a[1] = { "Test" }; 

The literal "Test" is in readonly memory,

Suggest:

char *a[1]; 
a[0] = strdup( "Test" ); 

and since strdup() can fail, check (!=NULL) the resulting pointer.

if( !a[0] )
{
    perror( "strdup failed" );
    exit( EXIT_FAILURE );
}

Then the code can modify via:

a[0][2] = 'e';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM