重新认识"数组"

    只要是程序员,相信使用数组已经是家常便饭了,但是您真的懂吗?  未必...

     本文章为原创,转载请注明出处,谢谢.

     作者 : 飞哥

1. 实数数组的初始化

    1.1 一维数组初始化

      方式1  :   
                    例1:
                     int arr[10] = {0,0,0,0,0,0,0,0,0,0};
                    该种初始化完全可以用以下方式代替
                     int arr[10] = {0};

                     例2:
                      int arr[10] = {1,2,3,4,5};
                      该种方式只对前五个数据赋值,那后五个数据是多少呢?
                      答案:  在{}方式下,未初始化的元素一律初始化为适当类型的0;
       方式2 :       
                    例如:
                               int arr1[] = {1,2,3,4,5,6,7,8,9,10}; //ok
                               int arr2[] = {1,2,3,4,5};          //ok
                    释义:  如果不明确定义数组的长度,则根据初始化表的长度确定数组的长度。
                              
      
       拓展1  : 如果数组没有初始化,那么将其值输出会是多少?  0还是不确定数字?
                     答案 : 为不确定的数字;   
                                int arr[10];
                                for(int i = 0; i < 10; i++) printf("%d",arr[i]);  //输出的都是不确定的数字
                     请对比方式1中的例2,以免混淆;

       拓展2 : 可以在代码中直接声明空数组吗?  
                      例如:    int arr[];         //error,目前还不支持;

        深入1:  
                       int a[10];
                       printf ("%d\n", sizeof (a));   
                       输出为 : 40  //较简单不再赘述;
                       
                       void   test(int szData[])
                      {
                             printf("%d",sizeof(szData));
                       }        
                       int szData[10];     
                       test(szData);    //输出为4,为什么?
                       答案: 函数调用过程中,形参与实参结合的过程实际上就是一个赋值的过程.
                                函数调用数组类型的参数时,形参得到的是实参数组的首地址,即:只是
                                 将实参数组首地址赋值给形参。所以形参实际上只是一个普通指针,编译器
                                  只知道其是个指针不知道其是否是数组形式的;
       深入2 :    int  szData[10];
                      printf ("%p\n", szData);   
                      printf ("%p\n", &szData[0]);
                      printf ("%p\n", &szData);
                      请问以上三个输出的地址相同吗?
                     第一个和第二个相同很好理解;关键是为什么第三个也和上面两个值相同呢?
                     因为 :printf ("%p\n", szData);   中szData代表的是数组首地址;
                            而 printf ("%p\n", &szData); 中szData代表的是整个数组,也就是说输出的是整个数组的首地址;
                     所以,一定要分清什么时候是代表整个数据,什么时候是代表数组首地址;
                     

     1.2  二维数组初始化

        1.2.1)概念巧解

              很多教科书上对二维数组的概念总是这样描述:
               二维数组是由多个一维数组组成的数组;
               这样的描述实在是糟糕透了,对于初学习的人来说在这句话上就得很大的劲去想象理解;
               为了简单理解其概念,我这样解释:
               二维数组  :  把一个一维数组分组后就变为二维数组,本质还是一维数组;
                                   例如:
                                   int arr[6] = {2,3,5,6,8,3};
                                   也可以用二维数组存放该组数据:
                                    int arr[2][3] = { {2,3,5},{6,8,3}}; 
                                   即 :   
                                    int arr[2][3] = {2,3,5,6,8,3} ;
                                    分组实际上就是把一个一维数组又分成了多个一维数组而已;
                                  再进一步 : 把一维数组转为二维数组
                                   例如: 
                                   int szData[10] = {8,3,5,6,2,9};
                                   int szMyData[][2] = &szData;等价于 : int (*szMyData)[2] = &szData
                 
             arr       :  类似一维数组,什么时候代表整个数组,什么时候代表的是数组首地址一定要分清;
             arr[i]    :  代表第i组的一维数组;
             arr[i][j] :   代表第i组的一维数组的第j个数据;
              

         1.2.2)二维数组初始化

               上面的概念中所讲例子属于一种初始化方式,接下来用举例的方式讲解其他方式:
               例如1: 
                          int arr[][3]  = {2,3,5,6,8,3} ;// ok
                          int arr[][]  = {2,3,5,6,8,3}; //error 
                为什么?
               答案:
                我们知道一维数组时初始可以写为: int arr[] =  {2,3,5,6,8,3};     
                编译器可以通过数组中有多少个数来确定分配空间的大小;
                但是对于二维数组:
                重点1:
                 未指定分组个数,只指定每组个数n : 
                 编译器会自动把每个组分为n个数,如果个数不足,则自动填充为0;
                 例如:  int arr[][4]  = {2,3,5,6,8,3} 等价于 int arr[][4] = {{2,3,5,6},{8,3,0,0}};
                 即: sizeof(arr) 值为  8 * 4 = 32;
                 既未指定分组个数,也未指定每组个数n : 
                编译器一头雾水,不知道该怎么为你的数组分组了,所以直接报错;
 
                 例如2 :  int arr[][3] = {{1},{3,5},{1,6,8}};//ok
                  为什么?
                  释义:   二维数组概念中我说其就是将一维数组分成多个一维数组,
                             二维数组支持 int arr[3] = {1};或者 int arr[3] = {3,5}这样的初始化方式
                             所以上面二维数组的写法没有错误;

            1.2.3) 二维数组作为参数传入函数

            为节省篇幅,举例说明:
            方式1  :
            例如:   
             void test(int szData[][4], int size)
            {
	        int i;
	       for (i = 0; i < size; i++) 
               {
		int j;
		for (j = 0; j < sizeof (szData[0]) / sizeof (szData[0][0]); j++)   //第1个数组大小除以一个数据大小为数组个数4
			printf ("%4d", szData[i][j]);
	       } 
            }

                   方式2 :
           例如: 
         void test(int* szData,int nDataCount)
	{
		int* pData = szData;
		for (int i = 0; i < nDataCount; i++)
		{
			printf("%d ",szData[i]);
		}
		
	}
        int szData[3][3] = {{1},{4,6,7},{8,3}};
	test((int*)szData,9);  //输出为:  100 467 830 </span>
            释义:  二维数组本质是一维数组。
          是不是有点一语点破醍醐灌顶的感觉呢?
              

 2.字符数组

   2.1)一维字符数组初始化

      例如:  char  szUser[] = "飞哥在此";
                   等价于:
                   char szUser[] = {'飞','哥','在','此','\0'};
              所以: sizeof(szUser) 值为9;
   2.2)表示字符串的三种方式:
         1)字面值方式:"hello"
         2)字符数组方式:char arr[10] = {'h', 'e', 'l', '\0'};
         3)字符指针方式:char* szData;
       区别:
        1)字面值存储在程序的静态存储区(全局区),其值不可改变。值相同的字面值内存地址一样。
        2)字符数组在内存堆栈区,其值可以改变,但数组本身的地址是一个常量不可被改变。
        3)字符指针存储的是一个地址,既可以指向字面值,也可以指向字符数组,对于前者字符的内容不能修改,而对于后者则可以修改。
    例1: 
           char* pName = "飞哥在此";
           pName[0] = "王";   //error!段错误或者程序崩溃
           为什么?
           释义:  pName指向的是一串字符串,该字符串以字面值存在于静态存储区,是定死的,不可以被改变;
    例2:
             char szData1[10];
     char szData2[10];
             szData1 = szData2;//error
            为什么?
            释义:  数组本身的地址是指针常量,不可以被改变;
      


    2.2)二维字符数组初始化

       方式1 :  char szName[2][64] = {"飞哥","小刘"};
       方式2:   char* szName[] =  {"飞哥","小刘"};   


3.使用数组注意点

   3.1)数组名不能与其它变量名相同
       例如:
     void main()
    {
      int a;
      float a[10];//error
      ……
    }
  3.2)不能用变量表示元素的个数, 但是可以是常数或常量表达式
        
      例如:       
<pre name="code" class="cpp">void main()
{
   int n=10;
   int szData[n]; //error
}

 3.3)指针数组与数组指针区别?
  数组指针 :   存放数组的指针;   例如 :char (*pData)[5];  //pData就是存放数组的指针;
  例如: 
   
    int szData[][5] = {1,3,6,8,3,5,9};
    int (*pData)[5]; 
    pData = szData;
     
  指针数组  :  存放指针的数组;    例如:  char* pData[64];  //pData就是存放指针的数组;
 例如:
       
	int n1 = 1,n2 = 3,n3 = 5;
	int *p[10] = {&n1,&n2,&n3};

4.数组面试题

     下面题目有问题吗?如果有问题怎么修改?
char *strA() {
    char str[] = “Hello World”;
    return str;
}
  str[]数组是函数strA()的局部变量,当调用完这个函数后,局部变量str被销毁,所以返回的结果是不确定的。

修改如下:
const char* strA() {
    char *str = “Hello World”;
    return str;
}

 ”Hello World”是字符串常量,它位于静态存储区,其在程序内部内存位置是不会被改变的;


 




                    







                
       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值