【问题标题】:copy or assign one string to another string in a 2 dimensional array of pointers将一个字符串复制或分配给二维指针数组中的另一个字符串
【发布时间】:2016-04-06 21:17:16
【问题描述】:

首先,这是一个测试程序,我想测试一些特定的东西,我想看看它是否有效。假设我想将 x 分配给 arr[0][4] 并希望保留此更改,以便 arr[0][4] 在主函数中也是 x:

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

问题是我不能将 x 分配给 arr[0][4],程序就关闭了。我也试过strcpy,这个:

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

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

与 strcpy 相同,程序只是关闭。 我只能这样做:

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

考虑到 x 是一个我不知道的字符串(或来自 scanf 的字符串),这对我没有任何帮助。 因此,如果 x 来自 scanf,我如何将 x 分配给 arr[0][4]?任何帮助,将不胜感激!谢谢:)

【问题讨论】:

  • C 没有 string 类型。 char 的序列是否是“字符串”只是所使用函数的约定。请阅读 C 中的指针和数组。
  • 这一行:for(i;i&lt;=1;i++){ 存在逻辑错误。你的编译器应该告诉你这个问题。建议:for(i=0; i&lt;=1; i++){for(; i&lt;=1; i++){

标签: c arrays string char variable-assignment


【解决方案1】:

在第一个失败的函数示例中,您试图将一个自动字符串变量复制到一个只读的字符串文字。这就是函数失败的原因。 arr[0][4] 是一个指向字符串字面量的指针。

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

但是在第二个成功的例子中,你直接分配了一个 string literal 指针(就像你在第一个初始化中所做的那样)。

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

顺便说一句,注意两者之间的区别

char name[] = "Alex";

char *name = "Alex";

在第一种情况下,name 使用给定数据的副本进行初始化,并且它是可修改的。

在第二种情况下,name 只知道一个指针,它指向的文本(“字符串文字”)是不可修改的。

【讨论】:

  • 感谢您的回答!我想我确实明白你说的话。那么有没有办法实现我所需要的(x 到 arr[0][4] 而不直接分配字符串)。也许制作 x 全局指针之类的?
  • 在第一个失败的函数示例中,您试图将动态字符串复制到字符串文字,这是只读的。不,事实并非如此。跨度>
  • 您需要先使用malloc 为字符串指针数组元素分配内存(允许字符串终止符!)然后复制字符串文字,而不是将它们的指针分配给数组。当你需要一个不同的字符串时,它可能有不同的大小,所以你可以realloc该数组元素的内存。
  • @hacks 稍作调整,感谢“动态字符串”到“自动字符串变量”。另一部分是正确的,尽管您的 cmets 在另一个答案下。
  • 我认为 hacks 很困惑,因为你们对实现的编号不同。对于黑客,使用strcpy 的实现是第二个,因为第一个实际上在问题的第一个代码块中(参见他的帖子)。
【解决方案2】:

这个方法

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

不起作用,因为您正在分配一个具有自动存储(又名“本地”)持续时间的变量。一旦函数返回,它就不再存在了。这是未定义的行为

这个方法

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

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

不起作用,因为 arr[0][4] 指向字符串文字。您不能修改字符串文字。同样,这是未定义的行为

这个方法

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

如果您只有指针并且没有为这些指针的指针分配任何内存,那么这是唯一正确的方法。

如果 x 来自 scanf,我如何将 x 分配给 arr[0][4]?

对于这种情况,您需要分配内存并将其分配给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()
}

虽然这很混乱。该数组具有指向字符串文字的指针。但只是arr[0][4] 指向一个malloc'ed 内存。如果您希望能够修改它或稍后调用free() 时,您需要跟踪这些指针 就可以了。

如果您希望能够修改它们,我建议您只使用 arrays 而不是指针数组,因为很难跟踪各种被 malloc 的指针并且其余指针指向at 字符串字面量。

【讨论】:

  • 您不能修改字符串文字,但可以修改指向字符串文字的指针。
  • @hacks 在strcpy(arr[0][4], x);
  • 那么有没有办法只创建一个二维字符串数组?因为我搜索如何创建字符串数组,而我发现的只是指针可以解决问题。
  • @MartinZabel;我想我在这里混淆了两个答案,你的和风向标。删除了我的cmets。很抱歉。
  • @OnceUaT 看看弗拉德的回答,也许这就是你想要的
【解决方案3】:

arr 的所有元素都是指向char 的指针。你在main 中初始化了它们,没有分配内存。他们只是指向字符串文字。

changeE第一版

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

不起作用,因为x 是一个自动局部变量,返回指向它的指针会导致未定义的行为。

在函数中

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

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

strcpy 不起作用,因为arr[0][4] 指向字符串文字并且无法修改。您可以通过为其分配空间来修改arr[0][4]

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

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

【讨论】:

    【解决方案4】:

    首先,你应该初始化你的数组arr,这样它就不会包含无效的指针:

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

    changE 的第一个实现不起作用,因为char x[50] 是一个初始化为“Tinky”的局部变量(分配在堆栈上)。一旦函数返回,你就不能超出这个变量(通过取消引用指针)。

    使用strcpy 的实现不起作用,因为目标内存是无法覆盖的字符串文字“Douglas”(在main 中分配)。

    第一个实现的指针分配很好,但是你必须从堆中分配内存,就像在这个scanf 示例中一样:

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

    【讨论】:

      【解决方案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[0][4] = "Tinky";
      

      是正确的。

      但是,您想为数组的一个元素分配您要输入的某个字符数组的地址。 在这种情况下,数组的存储时长应该至少与二维数组的存储时长相同。

      唯一合理的方法是为可读字符动态分配内存,并将它们的地址存储在二维数组的元素中。

      您可以使用 POSIX 函数 strdup 来执行此操作。 例如

      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" );
      

      或者你可以自己编写这样的函数。

      在这种情况下,您还必须使用标准 C 函数 free 来释放由 strdup 或类似函数分配的所有内存。

      在函数changE中应该使用相同的方法

      例如

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

      【讨论】:

      • 我打算自己建议strdup 方法。但是,现在,changE 应该在重新分配之前执行free(arr[0][4])。实际上,realloc 也可以。如果你清理一下,我很乐意投票。
      • 而且,您也许应该在changE 中使用scanf 示例。
      【解决方案6】:

      一个可能的解决方案是使用字符数组而不是指向字符的指针,如下所示。在本例中,字符串的最大长度为 50。

      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]);
      }
      

      【讨论】:

      • 你应该明确提到最大字符串长度现在是 50。你应该尊重scanf 调用。
      • Ups,首先,我必须纠正我,因为终止 NUL 字符,最大字符串长度为 49。所以如果有人在scanf提示符处输入50个字符,那么终止NUL字符将被写入arr[0][4][50],这超出了arr[0][4]的限制,因此,NUL字符实际上被放置在arr[1][0][0]。因此,您必须使用scanf("%49s") 定义调用中的最大字符串长度,例如。
      猜你喜欢
      • 1970-01-01
      • 2019-10-13
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-05
      相关资源
      最近更新 更多