铅笔

在你的害怕中坚持的越多,你就会越自信
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

数组作为函数的参数

Posted on 2016-12-21 12:42  黑色の铅笔  阅读(32102)  评论(0编辑  收藏  举报
《c和指针》》上有一段:

指针和数组并不是相等的,

当声明一个数组时,它同时也分配了一写内存空间,用于存储数组元素,

但当声明一个指针时,它只分配了用于容纳指针的空间(32位中4个字节的大小)。

如:

int a[5];
int *p;
a和p都具有指针值,都可以进行间接访问和下标引用操作。但是他们还是存在很大区别:
声明一个数组时,编译器将根据声明所指定的元素数量维数组保存内存空间,然后再创建数组名。他的值是一个常量,指向这段空间的起始位置。
声明一个指针变量时,编译器只为指针本身保留内存空间。而且指针变量并未初始化为任何现有的内存空间。
 
因此上述声明之后,*a是完全合法的,*p将会访问内存中某个不确定的位置。另外表达式p++可以通过编译,但a++却不可以,原因是a的值是一常量 p是一个变量;
 
一维数组访问
       以下标方式  array[i]      
       以指针方式  *(array+i);
 
   数组名是隐含意义的常指针(直接地址:数组第一个元素的地址)        其关联类型是数组元素的类型

站在c++编译器的角度, *p 相当于我们程序员手工(显示)利用间接赋值,去操作内存

"[]"是c++编译器帮我们程序员做了一个*p的操作

当一个数组名作为函数参数时,数组名的值就是指向数组第一个元素的指针,所以此时传递给函数的是指针的拷贝。

#include <iostream.h>
int  sum ( int  ap[ ] ,  int  n )
{
   int  m = 0 ;
   for ( int  i = 0 ;  i < n ;  i ++ )
    { 
       m += * ap ; 
       ap ++ ;
    }
    return m;
}
void main()
{   
    int  a [ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ;
    cout << "sum = " << sum ( a , 10 ) << endl ;
}

 

int  sum(int  ap[], int  n)  和int  sum(int  *ap, int  n)效果一样的

指针作为函数形参和数组作为函数形参是一样的.

 

二维数组名同样代表数组首元素的地址

//int b[2][5]===>b的类型为int(*)[5]不是char**

 多维数组名的本质:数组指针即指向一个数组的指针

int a[3][5]

(a+i) 代表是整个第i行的地址  

*(a+i)就表示第i行首元素的地址

*(a+i) + j  ===> &  a[i][j]

*( *(a+i) + j) ===>a[i][j]元素的值

 

 

 

 

 

一级指针做函数参数:

int array(char buf[60]);会退化为指针
int array(char buf[])
int array(char * buf)
二级指针做函数参数
int array2(char array[10][30])//10无作用 30确定其步长
int array(char array[][30])
int array(char (*array)[30])//数组指针的

 

二维数组可以看做是一维数组

二维数组中的每个元素是一维数组

二维数组参数中第一维的参数可以省略

void f(int a[5])     ====》void f(int a[]);      ===》 void f(int* a);

void g(int a[3][3])====》 void g(int a[][3]); ====》 void g(int (*a)[3]); 

 

 实参   ( 数组参数     ) 所匹配的形参(等效指针参数)
一维数组 char a[30]   指针 char*   (可直接char* p=a;下面的类似)
指针数组 char *a[30]     指针的指针 char **a 指针的指针([30]数组做函数参数退化为指针 , 况且又是个指针数组所以**)
二维数组 char a[10][30]       数组的指针 char(*a)[30](数组指针
数组指针(行指针)char(*c)[10]      char(*c)[10]    不改变
指针的指针  char**c(二重指针)  char**c            不改变

 

int    printfArr23_1(char myArray[10][30], int iNum)
{
    int i = 0;
    for (i=0; i<iNum; i++)
    {
        printf("%s \n", myArray[i]);
    }
    return 0;
}
int printf2Array_2(char myArray[][30], int iNum)
{
    int i = 0;
    for (i=0; i<iNum; i++)
    {
        printf("%s \n", myArray[i]);
    }
    return 0;
}
int printf2Array_3(char (*myArray)[30],int iNum)
{
    int i = 0;
    for (i=0; i<iNum; i++)
    {
        printf("%s \n", myArray[i]);
    }
    return 0;
}
void main()
{
    int i = 0;
    char myArray[10][30] =  {"ccccc", "aaaa", "bbbb","11111"}; //
    printf2Array_2(myArray, 4);
    printf2Array_3(myArray, 4);
    system("pause");
}

多维数组名本质就是一个数组指针

 

二重指针的用法

(1)二重指针指向一重指针的地址

(2)二重指针指向指针数组的

(3)实践编程中二重指针用的比较少,大部分时候就是和指针数组纠结起来用的。

(4)实践编程中有时在函数传参时为了通过函数内部改变外部的一个指针变量,会传这个指针变量的地址(也就是二重指针)进去。

 

 

 

int main()
{
    char* str[] = {"abcde","aqw","ulk"};
    char **str1 = str;// { "abcde", "aqw", "ulk" };不可以直接定义 **str1 =  { "abcde", "aqw", "ulk" };指针数组指针
    cout << "sizeof(str)" << sizeof(str) << endl;
    cout << "sizeof(str[1])" << sizeof(str[1]) << endl;
    cout << "sizeof(str[0])" << sizeof(str[0]) << endl;
    for (int i = 0; i < sizeof(str) / sizeof(str[0]);i++)
    {
        printf("%s\n", str1[i]);
    }system("pause");
    return 0;
}
char* str[] 与char **str1相等只适用于形参 或者char **str1指向char* str[]
 

华为的面试题:

若有函数声明voidf(char** p),则使得函数调用f(var)不正确的var定义是———?

A   char var[10][10];                                 B   char *var[10]

C   void* var=NULL;                                 D   char* v=NULL,**var=&v;

 

解析:

1.char var[10][10];var的类型是 char (*)[10] 类型(不理解的话需要好好看看课本)
2.char *var[10]; var数组是存放char *类型的数组,数组名var是数组var元素的首地址,所以var的
类型是char**类型
3.void * 是定义没有指针类型的指针,void *可以指向任何类型的数据。在c99中举个例子int *p = malloc(sizeof(int)); 可以不写强制类型转换,因为malloc返回一个void *类型的指针,

char**p = malloc(100);  这样定义一样可以通过
4.v是char*类型的,那么取v的地址肯定是char**类型的,所以var是char**类型的。

 

结构体变量作为函数形参的时候,实际上和普通变量(类似于int之类的)传参时表现一样的。所以说结构体变量其实也是普通变量。

用结构体变量作实参时,采取的是“值传递”的方式