关于C指针的问题

时间:2015-06-12 18:20:08

标签: c arrays pointers

在下面的代码中,我创建了一个整数数组,并尝试使用DisplayIntArray函数进行打印,以尝试理解指针的工作方式。

评论中嵌入了一些问题。

/*==========================================================
 * pointer tests
 *========================================================*/

#include <stdio.h>

void DisplayIntArray(char *Name, int *Data, int lenArray) {
  /* Display integer array data */
  int m;
  printf("%s = \n", Name);
  for(m = 0; m < lenArray; m++, printf("\n")){
    printf("%d ", *(Data+m));
    printf("%d ", Data[m]);
    // how come these two print statements display the same thing?
  }
}

void DisplayDoubleArray(char *Name, double *Data, int lenArray) {
  /* Display double array data */
  int m;
  printf("%s = \n", Name);
  for(m = 0; m < lenArray; m++, printf("\n")){
    printf("%f ", *(Data+m));
    printf("%f ", Data[m]);
  }
}


int main ()
{

  int int_array[5] = {1, 2, 3, 4, 5};
  int *int_array_p = &int_array[0];

  // print array with function DisplayIntArray
  // this works fine
  DisplayIntArray("int array", int_array_p, 5);
  printf("\n");


  // Curiously the function still works when passing the actual
  // array instead of the pointer.
  DisplayIntArray("int array", int_array, 5);
  printf("\n");


  // print array using the wrong function
  // This print should fail because I'm passing an integer value pointer
  // into a double. But shouldn't it print the first element
  // correctly? - Why not?
  DisplayDoubleArray("int array", int_array_p, 5);
  printf("\n");


  return 0;
}

代码的输出是:

int array = 
1 1 
2 2 
3 3 
4 4 
5 5 

int array = 
1 1 
2 2 
3 3 
4 4 
5 5 

int array = 
0.000000 0.000000 
0.000000 0.000000 
0.000000 0.000000 
-0.000000 -0.000000 
0.000000 0.000000

5 个答案:

答案 0 :(得分:2)

在C中,如果指针p指向数组且值为i,则p[i]*(p+i)相同。它们都评估到数组的i - 元素。

鉴于此,

是有意义的
printf("%d ", *(Data+m));
printf("%d ", Data[m]);

打印同样的东西。

你说:

// Curiously the function still works when passing the actual
// array instead of the pointer.

当在表达式中使用数组变量(例如对DisplayIntArray的调用)时,变量将计算指向第一个元素的指针。因此,

   DisplayIntArray("int array", int_array_p, 5);
   DisplayIntArray("int array", int_array, 5);

是等价的。

你说:

// This print should fail because I'm passing an integer value pointer
// into a double. But shouldn't it print the first element
// correctly? - Why not?
DisplayDoubleArray("int array", int_array_p, 5);

这里,参数中使用的参数类型和变量不匹配。使用gcc,我收到以下警告:

soc.c: In function ‘main’:
soc.c:51:35: warning: passing argument 2 of ‘DisplayDoubleArray’ from incompatible pointer type
   DisplayDoubleArray("int array", int_array_p, 5);
                                   ^
soc.c:18:6: note: expected ‘double *’ but argument is of type ‘int *’
 void DisplayDoubleArray(char *Name, double *Data, int lenArray) {

通过该调用,程序应该表现出未定义的行为。

答案 1 :(得分:2)

  

printf(&#34;%d&#34;,*(Data + m));
  printf(&#34;%d&#34;,Data [m]);
  //这两个打印语句怎么显示相同的东西?

因为他们意味着同样的事情; Data [m]和m [Data]在这里都相当于*(Data + m),它们都引用相同的元素。

  

//奇怪的是,当传递实际时,该功能仍然有效   //数组而不是指针。

当你尝试在像这样的表达式it automatically "decays" into a pointer to the array中使用数组时,这意味着你不能传递数组本身,只能指向它。

  

//使用错误的功能打印数组
  //这个打印应该失败,因为我传递了一个整数值指针
  //成双但是不应该打印第一个元素
  //正确吗? - 为什么不呢?

这是未定义的行为,理论上任何事情都可能发生。在实践中,您的编译器很可能会尝试解释int数组的原始位模式,就好像它是一个双数组,并且恰好对应于非常接近0.0的浮点值。
它很可能不会正确地打印第一个元素,因为int和double在内存中的存储方式不同。

答案 2 :(得分:1)

printf("%d ", *(Data+m));
printf("%d ", Data[m]);
  

这两个印刷语句怎么显示相同的东西?

它们显示相同的内容,因为指针p指向至少m + 1元素的数组,表达式*(p + m)p[m]意味着完全同样的事情。他们是100%的同义词。如果您愿意,可以将其作为指针算术定义的一部分。

int int_array[5] = {1, 2, 3, 4, 5};
int *int_array_p = &int_array[0];
  

这很好用:

DisplayIntArray("int array", int_array_p, 5);
  

奇怪的是,当传递实际数组时,该函数仍然有效:

DisplayIntArray("int array", int_array, 5);

是的,因为在大多数情况下,数组名称会自动转换为指向数组第一个元素的指针。顺便说一下,这与你之前提出的问题相吻合。

  

不应该[这]正确打印第一个元素吗? - 为什么[它]不是?

DisplayDoubleArray("int array", int_array_p, 5);

DisplayDoubleArray()中,你假装指针参数指向double表示的字节,但事实并非如此。因此,取消引用指针会产生未定义的行为。

假设观察到的实际行为是产生double类型的值 - 这是合理的可能但不一定是这种情况,因为行为未定义 - 然后告诉printf()它正在接收类型为float的值。因此,printf()的行为未定义。可能printf()解释(未定义的)sizeof(float)值表示的前double个字节,就像它们是float值的表示一样,但同样,未定义。在任何情况下,doublefloat的表示肯定与int的表示不同,并且它们通常也彼此不同。没有理由认为数组的任何元素都应该以这种方式正确打印。

此外,类型double的表示可能大于系统中int类型的表示形式(8字节double和4字节int是共同)。如果是这样,那么执行DisplayDoubleArray()将尝试访问基础数组的末尾,除非上述其他一些未定义的行为阻止它执行此操作。访问数组末尾会产生未定义的行为。

答案 3 :(得分:1)

大部分原因是array name is implicitly converted to a pointer to the first element of the array

有关其他详细信息,请参阅每个引用块下方的评论。

printf("%d ", *(Data+m));
printf("%d ", Data[m]);
// how come these two print statements display the same thing?

那是指针算术。对于数组名称的转换,索引到数组与将索引添加到指向数组的第一个元素的指针(可以是数组本身的名称)完全相同。

// Curiously the function still works when passing the actual
// array instead of the pointer.
DisplayIntArray("int array", int_array, 5);

见上文。

// print array using the wrong function
// This print should fail because I'm passing an integer value pointer
// into a double. But shouldn't it print the first element   
// correctly? - Why not?  
DisplayDoubleArray("int array", int_array_p, 5);

它应生成有关隐式指针转换的编译器警告。如果没有,启用警告,如果仍然没有出现,则删除编译器或踢出供应商。将一个指针转换为另一个指针只能保证将其转换回来而不会丢失信息。对转换指针的任何访问都是未定义的行为。这意味着任何事情都可能发生。你的电脑可能长出牙齿咬你。 猜测可能发生的事情毫无价值,只是不要这样做!

仅供参考:intfloat / double的二进制表示形式差别很大,毫不奇怪。

答案 4 :(得分:0)

int *int_array_p = &int_array[0];

仅在您想要独立于数组范围操作内存地址时才有用。否则,您必须知道数组会衰减到指向数组第一个元素的指针。

因此&int_array[0];int_array相同。 它们都返回数组的偏移地址。 您不必使用引用运算符&,因为它返回&#34;&#34;的地址和指针已经是&#34;

的地址 保证

double最多为8个字节,而int保证最多为4个字节(在x64位体系结构上排除一些罕见的情况)。 将整数数据类型引用到指向double的指针是未定义的行为,现代编译器会给出警告。 但是,如果您要求将值打印为%i%d,则可能会为您返回正确的结果,否则会读取更大的内存区域,并且根据您的字节顺序,它将会给你各种意想不到的结果。