【问题标题】:invalid type argument of the unary '*' (have int)一元'*'的无效类型参数(有int)
【发布时间】:2021-10-15 17:43:49
【问题描述】:

如您所见,我使用 printf 函数使用指针打印二维数组,但我收到无效类型参数的错误。为了检查,我尝试打印下面的代码,我用k 和指针c 打印k 的值。我没有错误

int main ()
{

    int a[3][2]={2,5,9,11,23,46};
    int *p;
    p=&a[0][0];
    for(int i=0;i<=2;i++)
    {
        for(int j=0;j<=1;j++)
        {
            printf("\n value of the 2 d array: %d",*(*(p+i)+j));
        }
    }
    int k=6;
    int *c;
    c=&k;
    printf("%d",*c);
}

【问题讨论】:

  • *(p+i*2+j)? (我不确定这是否会引发未定义的行为)
  • @Subhendu Nayak 错误信息有什么不清楚的地方?
  • *(p+i) 是一个整数,*(p+i) +j 是一个整数,并且没有定义 *(integer)。正如 MikeCAT 所说,使用 *(p + 2*i + j)
  • @MikeCAT:给定p = &amp;a[0][0];p 指向int [2] 中的一个元素,并且p+i*2+j 仅定义为 0 ≤ i*2+j ≤ 2,根据 C 2018 6.5。 6.尽管在a[0][1] 之后内存中还有更多int 对象,但指针算法并未在a[0] 及其名义端点&amp;a[0][2] 中的元素之外定义。此外,由于首先执行+i*2,因此仅在满足 0 ≤ i*2 ≤ 2 和 0 ≤ i*2+j ≤ 2 时才定义p+i*2+j
  • @susanth29:因为行为不是由 C 标准定义的,所以我们无法知道代码是否可以工作(除非编译器指定它将作为语言的扩展工作)。在某些情况下,编译器优化可能会破坏尝试越界访问子数组的代码。

标签: c pointers multidimensional-array implicit-conversion dereference


【解决方案1】:

你声明了一个指向int的指针

int *p;

所以你只能取消引用一次,如果你这样做,你会得到一个 int 类型的对象,你不能应用一元运算符 *。

就是在这个表达式中

*(*(p+i)+j)

子表达式

*(p+i)

已经拥有int 类型。因此,此子表达式 *(p+i)+j 也具有您要取消引用的 int 类型。

需要通过以下方式声明指针p

int ( *p )[2];
p = a;

现在是表达式

(p+i)

指向二维数组ai-th“行”。解引用指针表达式

*(p+i)

您将获得int[2] 类型的数组“行”。在表达式中使用它会隐式转换为指向其第一个元素的指针。因此这个表达式

*(p+i)+j

具有int * 类型并指向数组ai-th“行”的j-th 元素。

取消引用这个指针表达式

*(*(p+i)+j)

你会得到i-th“行”的j-th元素。

【讨论】:

    【解决方案2】:

    由于p 的类型为int *,表达式*(p + i) 的类型为int,因此*(p + i) + j 的类型为int,并且不能被取消引用。

    将表达式*(*(p + i) + j) 替换为*p++

    printf("\n value of the 2 d array: %d", *p++);
    

    将“行走”p 穿过数组;它开始指向a[0][0],然后++ 运算符将指针前进以指向下一个元素。

    【讨论】:

      【解决方案3】:

      您收到此错误的原因是因为*(*(p+i)+j) 无效,让我们分解一下:

      (*p+i) p 存储二维数组中第一个元素的地址,即 2。您已将 i 的值添加到地址中,然后将其封装在 *() 中,该地址是地址并返回整数。

      现在的表达式在第一次迭代中将如下所示:

      *(*(p+0)+j)

      *(2+j) // 这将变得无效,因为您正在尊重一个整数

      解决此问题的方法很简单。创建一个指向整数数组的指针。

      int (*p)[2] = a;

      这样做的原因是因为您的数组有 3 行 2 列,所以使用它更容易在 2d 数组中移动:

      int a[3][2]={2,5,9,11,23,46};

      您可以在视觉上想象如下:

      {2,5}
      
      {9,11}
      
      {23,46}
      

      现在您可能会看到我们是否单独引用每个数组会变得更容易。

      int main ()
      {
          int a[3][2]={2,5,9,11,23,46};
      
          int (*p)[2] = a;
      
          for(int i=0;i<=2;i++)
          {
              for(int j=0;j<=1;j++)
              {
                  printf("%d ", *(*(p+i)+j));
              }
          }
      }
      

      这次让我们分解*(*(p+i)+j)

      *(p+i)p 存储第一个数组的地址,然后我们将 i 添加到它,并将它带到数组的第一个元素。然后我们添加 j 也就是沿着数组移动。最后最外层的*() 取消引用这个地址并给我们一个int 值来打印。

      【讨论】:

        猜你喜欢
        • 2011-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多