【问题标题】:Passing Pointer To An Array Of Arrays Through Function通过函数将指针传递给数组数组
【发布时间】:2010-09-29 04:37:39
【问题描述】:

代码中有一个指向数组的指针,即 NameList。我希望将 Pointer(NameList) 中每个数组的内容一一打印出来。下面的代码无法完成任务。请。帮助。

int Data1[] = {10,10};
int Data2[] = {20,20};
int Data3[] = {30,30};

int *NameList[] = {Data1, Data2, Data3};
main()
{  Function(NameList); }

Function(int *ArrayPointer)
  {
    int i, j, index=0;
    for (i=0; i < 3; i++)
      {
        for (j=0; j < 2; j++)
          {
             //It does not print the data
             printf("\nName: %s",  ArrayPointer[index++]);
          } 
        index=0;         //Counter reset to 0
        ArrayPointer++;  //Pointer is incremented by one to pick next array in the pointer
      }
  }
print("code sample");

问题原始海报的另一条注释:

我在 Turbo C 中完成了一个吃豆人游戏。我正在完善一些图形例程,以便可以轻松地再次重复使用它。这只是为了帮助和理解概念而创建的一个小样本。代码中的所有数据实际上都是精灵的字符数组。现在我只想调用一个传递指针的函数,以便将指针中的每个数组都绘制到屏幕上。如何修改此代码以处理此问题?我居然卡在这里了。

【问题讨论】:

  • 你为什么回滚我的提交?我添加了适当的标签(C 和 C++),并通过将源代码放在 Markdown 的“代码标签”下来使源代码可读......
  • 我没有回滚,但我确实重新格式化了。
  • 可能涉及到错误吗?如果他在您重新标记时对其进行了编辑,那么他所做的更改可能会自动恢复您的更改?
  • 我也遇到了这种情况,被 OP 分心并抱怨 :)
  • 您应该收到将 NameList 传递给 ArrayPointer 的警告:NameList 是一个 int 指针指针值,因此 ArrayPointer 应该是一个 int 指针指针,而不是一个 int 指针。或者你应该调用 Function(*NameList),而不是 Function(NameList)。

标签: c++ arrays pointers


【解决方案1】:
int Data1[]

类型为

int *

和

int *NameList[]

类型为

int **

那里有一个二维数组。您的意思很可能是:

Function(int **ArrayPointer)

注意,ANSI C/C89/C99 函数有一个明确的返回类型(或void),例如

int main() { ... }
void Function() { ... }

ArrayPointer 指向的值是int,而不是字符串。因此

printf("\nName: %s",  ArrayPointer[index++]);

应该写成别的东西。

第三件事:index == j 在您的代码中。因此,index 可以被删除以支持j。

i 和 j 在这里可能不是好的变量名,因为 ArrayPointer 不是描述某物列表的名称。

如果您需要更多帮助,请发布您要执行的操作,因为您的代码中有几个错误(和奇怪的地方)。

【讨论】:

  • int* 是指向 int 的指针,int[] 是 int 的数组(长度未指定)。它们是根本不同的类型。如果有一个函数int f(int b) { return data[b]; },那么它将意味着不同的东西 - 并生成不同的代码 - 如果数据被声明为int* data; vs. int data[];
  • charles,你可以有不完整数组类型的数据:extern int data[];如果我没记错的话,那么做 data[b] 的意思就好像 data 是 int* 一样。 (你不能接受它的大小。如果 data 没有在(当然)完整的数组类型之间定义,那么 sizeof(data) 将是一个错误)。
  • 可以声明main(int argc, char * argv[])。
  • @litb,看看一些生成的汇编程序,如果data是extern int[],那么data[n]是指数据地址之外的数据位置n * sizeof int。如果 data 是 extern int* 则 data[n] 从 data 加载一个指针值,并相对于 stored 在 data 处的指针值进行访问。
  • 是的,您可以将 main 声明为 int main(int argc, char* argv[]) 因为函数的类型是通过将“T 数组”类型的所有参数转换为“指向 T 的指针”来确定的”。这并不意味着在函数声明之外的类型 int[] 和 int* 在某种程度上是相同的。
【解决方案2】:

从你的“answer”来看(你真的应该编辑你的原始帖子并添加这些信息),你可能想要这样的东西:

void draw_all_sprites(Sprite *sprites, size_t num_sprites)
{
    Sprite *cur_sprite;
    size_t i;

    for(i = 0; i < num_sprites; ++i)
    {
        draw_sprite(cur_sprite);
        ++cur_sprite;
    }
}

一个相当简单的 for 循环遍历数组中的元素。

【讨论】:

    【解决方案3】:

    main 必须返回一个类型。您忘记将“int”作为返回类型(C++ 中禁止使用隐式 int)。

    话虽如此,我不确定你的意思

    // It does not print the data
    printf("\nName: %s",  ArrayPointer[index++]);
    

    ArrayPointer[index++] 将按照参数列表中的定义返回一个int。那应该如何存储 name ?它将存储一个整数!

    再说一次,就是说,您不能使用该特定参数调用该函数(双关语)。让我们查看您的类型:

    int Data1[] = {10,10};
    int Data2[] = {20,20};
    int Data3[] = {30,30};
    
    int *NameList[] = {Data1, Data2, Data3};
    
    Data1      Data2      Data3      NameList
    int[2]     int[2]     int[2]     int*[3]
    

    与您所说的相反,NameList 不是指向数组数组的指针。我觉得我需要向您展示那将是什么:

    int (*NameList)[N][M] = Some3DimensionalArray;
    

    这根本没有意义。那你有什么?

    Data1 = array of 2 int
    Data2 = array of 2 int
    Data3 = array of 2 int
    NameList = array of poiners to int
    

    那就是你得到的。然后你将NameList 传递给一个需要指向int 的指针的函数。当您在main 中调用Function 时,它必须已经失败!我不知道你在 Function 的那一行中所说的 name 是什么意思。但是如果你想打印出存储在指向的数组中的整数(通过指向它们的第一个元素的指针),你可以这样做(尽可能地保留你的代码):

    // don't forget the return type, mate. Also see below
    void Function(int **ArrayPointer)
      {
        int i, j, index=0;
        for (i=0; i < 3; i++)
          {
            for (j=0; j < 2; j++)
              {
                 // It does not print the data. It is not a string, 
                 // but an int!
                 printf("\nName: %d\n",  ArrayPointer[i][index++]);
              } 
            index=0;         //Counter reset to 0
            // no need to increment the pointer. that's what the indexing by i 
            // above does
            // ArrayPointer++;  
          }
      }
    

    我一直在鼓吹人们问指针和数组之间的区别。编写正确的代码至关重要。我希望我能帮上忙。最后,稍微谈谈int[] 和int* 之间的区别。第一个是不完整的数组类型,而第二个是完整的类型(指向 int 的指针):

    typedef int Single[]; // array of indeterminate size.
    typedef int *Pointer; // pointer to int
    
    Single s1 = { 1, 2, 3, 4 }; // works!
    Pointer s2 = { 1, 2, 3, 4 }; // no no, doesn't work. s2 wants an address
    

    s2 的类型现在有一个类型不同于 int[],因为您初始化了类型不完整的数组,数组s1 在定义后变得完整。它的类型为int[4]。然而,在参数列表中,存在一个特殊规则,它将导致任何数组类型(甚至是完整的数组类型!)都等同于指向其第一个参数的指针。因此:

    void f(int *a) <=> void f(int a[]) <=> void f(int a[42]);
    void f(int (*a)[42]) <=> void f(int a[][42]) <=> void f(int a[13][42])
    // ...
    

    那是因为你不能按值传递数组。编译器滥用 使数组类型等同于指向它们的第一个元素的指针。同样处理函数:

    void f(int a()) <=> void f(int (*a)())
    

    因为你不能按值传递函数(嗯,对我来说根本没有意义),编译器滥用它使参数列表中的函数类型等同于指向该函数类型的指针。

    【讨论】:

    • 我的固定示例出现分段错误。我认为由于您在外循环中递增 ArrayPointer,因此您需要 (*ArrayPointer)[index++] 而不是 ArrayPointer[i][index++]。当然更好的方法是 ArrayPointer[i][j] 并且根本不用索引。
    • 啊,是的,没有注意到 ArrayPointer 的增量。谢谢:)
    【解决方案4】:

    该死的litb,你又一次以几分钟的优势击败了我。 (要是我没有孩子一直醒就好了……)

    啊,什么鬼。也许这对某人仍然有用。


    哦,只是为了确定这件事:

    • 数组,例如 int a[4] 为其数据分配内存空间。
    • 指针,例如 int * p 只为指向内存中另一个位置的指针分配足够的内存空间。
    • 这就是为什么我们可以在数组上使用 sizeof 并获得完整的内存占用,但不能在指针上使用。

    除了那一点点区别之外,int[] 和 int* 之间并没有太大的区别。 (考虑有多少人声明 *main(int argc, char **argv) vs main(int argc, char * argv[])。)


    注意:这里所有的内存地址都是虚构的。我只是为了说明一个观点而编造它们。

    给定:

    int Data1[] = {10,11};
    int Data2[] = {20,22};
    int Data3[] = {30,33};
    

    我们现在有 3 个内存块。说:

    0xffff0000-0xffff0003  with a value of (int)(10)
    0xffff0004-0xffff0007  with a value of (int)(11)
    
    0xffff0008-0xffff000b  with a value of (int)(20)
    0xffff000c-0xffff000f  with a value of (int)(22)
    
    0xffff0010-0xffff0013  with a value of (int)(30)
    0xffff0014-0xffff0017  with a value of (int)(33)
    

    地点:

    Data1 == & Data1 [0] == 0xffff0000
    Data2 == & Data2 [0] == 0xffff0008
    Data3 == & Data3 [0] == 0xffff0010
    

    不,我不要在这里讨论大端字节序与小端字节序!

    是的,在这种情况下,Data1[2] == Data2[0]。但是你不能依赖你的编译器把东西放在内存中,就像我在这里放置它们一样。

    下一步:

    int *NameList[] = {Data1, Data2, Data3};
    

    所以我们现在有了另一块内存。说:

    0xffff0018-0xffff001b  with a value of (int*)(0xffff0000)
    0xffff001c-0xffff001f  with a value of (int*)(0xffff0008)
    0xffff0020-0xffff0023  with a value of (int*)(0xffff0010)
    

    地点:

    NameList == & NameList [0] == 0xffff0018
    

    注意,NameList 是 int ** 类型,并且 NOT int* 类型!

    我们可以这样写:

    void Function(int **ArrayPointer)
    {
      for ( int i=0; i < 3;  i++ )
        for ( int j=0; j < 2; j++)
          printf("Name: %d\n",  ArrayPointer[i][j] );
    }
    
    int main() {  Function(NameList); }
    

    ArrayPointer 解析为 (int**)0xffff0018。

    ArrayPointer[0] == *( (int**) 0xffff0018 ) == (int*)(0xffff0000) == Data1。

    ArrayPointer[0][1] == *( ( * (int**) 0xffff0018 ) + 1 ) == (int) * ( (int*)0xffff0000 + 1 ) == (int) * (int* ) 0xffff0004 == 数据1[1]。


    您可能需要查看指针算法:array[N] == *(array + N)

    【讨论】:

    • 对我很有帮助。感谢您在问题解决后发布。
    【解决方案5】:

    帕拉莫德,

    是否有一个函数需要调用,类似于

    void drawSprite(int *data, int rows, int cols)
    

    ?

    然后您需要将所有数据保存在一块内存中。在您的示例中,编译器为每一行分配一个单独的块,然后为另一个块分配三个指向行的指针。因此,数组被保存在 4 个不同的地方。

    您需要的是多维数组而不是数组数组。像这样初始化你的数据:

    int data[3,2] = {{10,10},{20,20},{30,30}};
    

    然后你可以这样调用你的函数:

    drawSprite(&data[0,0], 3, 2);
    

    使用多维数组将所有元素放在一块内存中。优点是,您可以将 piointer 传递给第一个元素,并且您知道所有其他元素的位置。缺点 - 所有行都分配相同的大小。

    【讨论】:

      【解决方案6】:

      我在您的程序中做了一些更正,请找到它们并进行比较。我知道现在回复太晚了。但我今天看到了这一点。

      int Data1[] = {10,10};
      int Data2[] = {20,20};
      int Data3[] = {30,30};
      
      int *NameList[] = {Data1, Data2, Data3};
      
      main()
      {  
        Function(NameList); 
      }
      
      Function(int *ArrayPointer)
      { 
          int i, j, index=0;
          for (i=0; i < 3; i++)
            {
              for (j=0; j < 5; j++)
                {
                   //It does not print the data
                   printf("\nName: %d\n", *((int *)ArrayPointer[i] + index));
               index++;
                } 
              index=0;         //Counter reset to 0
            }
        }
      

      说明:

      当您将 NameList 作为指向整数的指针传递给 Function 时,传递的是数组第一个元素的地址,它恰好是 Data1(数组的地址)。但由于该地址保存在整数数组中,因此将被视为整数。要使其表现得像数组的地址(或者,就此而言,指向 int 的指针),您需要将其强制转换为 (int *)。这就是我所做的:

      printf("\nName: %d\n", *((int *)ArrayPointer[i] + index));

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-15
        • 1970-01-01
        • 1970-01-01
        • 2017-06-29
        • 2016-03-27
        • 1970-01-01
        相关资源
        最近更新 更多