【问题标题】:C: Last element in char* array rewriting all array entriesC: char* 数组中的最后一个元素重写所有数组条目
【发布时间】:2017-11-02 18:22:23
【问题描述】:

我需要将文件中的一系列单字行加载到数组中,因此我创建了一个函数来执行此操作。该函数将char*** arr 作为参数,它是一个指向字符串数组的指针。我分配内存然后让这个循环将单词加载到数组中。

i=0;
FILE *fp = fopen(filename, "r");
while(fgets(tok, WORD_BUFFER, fp) != NULL){
  (*arr)[i] = tok;
  printf("Word %d:%s", i, (*dict)[i]);
  i++;
}
//arr is a char***, tok is a char[WORD_BUFFER], and WORD_BUFFER is 50

我的问题是,这似乎是用我试图输入到条目 [i] 的任何内容覆盖数组的每个条目。我这样说是因为上面循环的输出文件看起来像这样:

A
B
C
D

似乎打印正确,但是当我在主函数中打印数组时(甚至只是在那个函数的后面),它会打印出来:

D
D
D
D

我猜这与我对fgets 的使用或(*arr)[i] = tok 的分配有关,但我不确定。 谢谢!

【问题讨论】:

  • 此语句后 (*arr)[i​​] = tok ;数组的所有元素都具有相同的变量 tok 的值,
  • 这是为什么呢?为什么不只让 arr[i] 有 tok 的值呢?
  • 您只是在使用 = 运算符进行指针赋值。 tok 在循环中每次迭代都会被文件中的内容覆盖。所以一切都指向tok,这是从文件中读取的最后一行。如果您想保存数据,每次循环时都需要将 strcpy 来自 tok 的数据发送到不同的目的地。
  • @yano 谢谢!使用 strcpy 有效。我有点困惑,为什么一个简单的指针分配不起作用,因为我相信我在以前的一些工作中已经做到了,没有问题,但是,非常感谢!
  • 当然arr 必须有足够的空间来存储数据,如果没有,当您strcpy 并写入您不拥有的内存时,您会调用未定义的行为。这可能表现为段错误

标签: c arrays string fgets


【解决方案1】:

根据您的评论,我将尝试使用简单的char* 数组来解释您在做什么。假设您有以下内容:

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

int main(void)
{
  int i;
  char tok[50] = "applesauce";  // tok can contain up to 49 chars plus the NUL terminator

  char* myCharPtr[20];  // this is an array 20 long where each element is of type char*

  // All the loop does is store the _address_ of tok at each position in the
  // myCharPtr array.  The _data_ "applesauce" only exists _once_ in memory,
  // and whatever that address is now fills the contents of myCharPtr.
  // (technically, "applesauce" exists twice in memory, the string literal
  // and the char array.. but neither of those places are in myCharPtr)
  for (i=0; i<20; i++)
  {
    myCharPtr[i] = tok;
  }

  for (i=0; i<20; i++)
  {
    printf("myCharPtr[%d] = %s\n", i, myCharPtr[i]);
    // prints out "applesauce" for each entry because each entry points to tok.
  }

  // Now let's do

  strcpy(tok, "apples");  // "apples" is smaller than 49, so we aren't overwriting the bounds of the array

  for (i=0; i<20; i++)
  {
    printf("myCharPtr[%d] = %s\n", i, myCharPtr[i]);
    // prints out "apples" for each entry because the _pointer_ to tok
    // hasn't changed, but the _data_ in tok has changed.
  }

  // To further re-enforce this, you can do
  printf("address of tok = %p\n", (void*)tok);
  for (i=0; i<20; i++)
  {
    printf("address of myCharPtr[%d] = %p\n", i, (void*)(&myCharPtr[i]));
  }
  // the address for tok will match all the addresses in myCharPtr

  // if you want to actually save/copy the data in tok, then you need to do
  // something like this

  char wordList[20][50];  // this can store up to 20 words that are each up
                          // to 49 chars each (must leave 1 byte for NUL termination
  for (i=0; i<20; i++)
  {
    // assume this function populates tok with new data each call, much like fgets
    // this function would have to ensure it's not writing strings bigger than 49 to tok
    GetNewContentForTok(tok);
    strcpy(wordList[i], tok);
    // now, we are saving the contents of tok each time, not simply copying
    // its pointer.
  }

  for (i=0; i<20; i++)
  {
    printf("wordList[%d] = %s\n", i, wordList[i]);
    // this will print all the strings that were once stored in tok from the previous loop
  }

  return 0;
}

我通常会尽量避免处理char*** 类型,因为太多的间接性会让我感到困惑。我在上面的示例中使用了数组,但同样的原则也适用于指向动态分配内存的指针。

【讨论】:

    猜你喜欢
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 2014-10-10
    • 1970-01-01
    • 2017-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多