繁体   English   中英

如何修改C中字符串数组中的单个字符?

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

我有一个char**类型的数组,我需要修改其字符串中的单个字符。 它给了我一个分段错误。 最小的样本:

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

我理解将字符串声明为字符数组而不是char指针可以更改单个字符,如下所示:

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

但我不清楚如何使后一种技术在前一种情况下工作,或者至少,如何能够改变数组中包含的字符串中的单个字符,无论手段如何。

如果您正在寻找替代方案,这可以是一个

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

您可以复制字符串,以便进行编辑。 试图修改它是未定义的行为。 在您的情况下,未定义的行为会导致分段错误。 标准 §6.4.5¶7

如果这些数组的元素具有适当的值,则这些数组是否不同是未指定的。 如果程序试图修改此类数组,则行为未定义

而且,你可以像你一样做同样的事情 - 你可以用文字字符串初始化一个char数组 - 它是可修改的,因为正在创建字符串的副本。 (没有像字符串文字那样的非可修改性约束)。 此外,如果您知道要使用的所有文字都具有MAXLETTER字符数,那么您可以执行此操作

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

标准提到它§6.7.9¶14

字符类型数组可以由字符串文字或UTF-8字符串文字初始化,可选地用大括号括起来。 字符串文字的连续字节(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素

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

你声明a是一个指向char的单个指针的数组,即它可以看作是一个字符串数组。 并使指针指向文字字符串"Test" 问题是文字字符串是只读的

文字字符串可能不是常量,但仍然无法修改。 试图这样做会导致未定义的行为

char c[] = "Str";

你有一个包含四个字符的数组。 它不是常数,也不是只读的。 您可以将其修改为您的内容(只要您保持数组的边界,并且不要将字符串终止符修改为其他内容)。

情况1 :

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

在上面的语句中, a是一个array of char pointer ,看起来像

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

在这种情况下a[0][2] = 'e'; 是不可能的,因为您尝试更改RAM的read only部分。 你可以做a[0] = "hello"因为那时你正在改变可能的地址。

案例2:

char c[] = "Str";

在上面的语句中, c是am char array ,它的内容存储在RAM的stack部分,你可以修改它的内容,意思是c[1] = 'r'; 是可能的。

你的问题是如何修改它,它不可能用char*a[1] ,而不是char*a[1]你可以使用char a[1][10]然后它是可能的,这是一个解决方案。

您的另一种选择,除了标准的声明a作为一个字符的任意阵列是使用复合字面常量 ,以指针的指针初始化数组 ,而不是一个指向字符串文本 C99引入了复合文字 ,允许您初始化指向指定类型的指针。 它具有强制转换的一般形式,后跟初始化器。 在您的情况下,您将在指针数组中初始化单个指针,

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

复合文字是:

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

这会将指针元素a[0]初始化为指向数组指针,而不是指向string-literal指针 您的代码将如下所示:

#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;
}

示例使用/输出

$ ./bin/cmplitptp
s
e

正如在几种情况下所指出的那样,您选择将a声明为带有单元素的 char指针数组 ,这有点不同寻常。 一般来说,如果你想初始化一个字符数组,你只需要声明char a[] = "Test"; 但是,您也可以声明a 指向char的简单指针,并使用复合文字将该指针初始化为指向数组的指针,例如char *a = (char[]){ "Test" }; ,这将消除一个间接层面上的a简化您的代码:

#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;
}

(相同输出)

在练习时,您通常会看到用于初始化struct的复合文字,没有理由不能用它们来初始化数组。 将它添加到您的C-工具箱,并在实践中,如果你想要a作为初始化为一个特定的字符串数组,只需用char a[] = "Some String";

关于:

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

文字“测试”在只读内存中,

建议:

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

由于strdup()可能会失败,请检查(!= NULL)生成的指针。

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

然后代码可以修改:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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