1. 程式人生 > >陣列,結構體初始化為0

陣列,結構體初始化為0

一直以為 int a[256]={0};是把a的所有元素初始化為0,int a[256]={1};是把a所有的元素初始化為1.
除錯的時檢視記憶體發現不是那麼一回事,翻了一下《The C++ Programming Language》總算有定論。PDF的竟然不然複製,就把它這章翻譯了,如下

5.2.1   陣列初始化
陣列可以用一個列值來初始化,例如
         int v1[] ={1,2,3,4};
         char v2[]={'a','b','c',0};
當陣列定義時沒有指定大小,當初始化採用列表初始化了,那麼陣列的大小由初始化時列表元素個數決定。所以v1和v2分別為 int[4] 和char[4]型別。如果明確指定了陣列大小,當在初始化時指定的元素個數超過這個大小就會產生錯誤。例如:
         char   v3[2] ={'a','b',0};   //錯誤:太多的初始化值了
         char   v3[3] ={'a','b',0};   //正確

如果初始化時指定的的元素個數比陣列大小少,剩下的元素都回被初始化為   0。例如
         int   v5[8]={1,2,3,4};
等價於
          int   v5[8]={1,2,3,4,0,0,0,0};

注意沒有如下形式的陣列賦值:
         void f()
         {
             v4={'c','d',0};   //錯誤:不是陣列賦值
         }
如果你想這樣的複製的話,請使用 vector(16章第三節) 或者 valarray(22章第四節)。
        字元陣列可以方便地採用字串直接初始化(參考第五章 2.2小節)
         譯註: 就是 這樣啦   char   alpha []="abcdefghijklmn";

The C++ Programming Language ,Third Edition by Bjarne Stroustrup.

、、、、、、、、、、、、、、、、、、、、、、、、、、、///////

/////////////////////////////////////////////////////////////

6.6     集合初始化
顧名思義,集合(aggregate)就是多個事物聚集在一起,這個定義包括混合型別的集合:像struct和class等,陣列就是單一型別的集合。
初始化集合往往既冗長又容易出錯,而C++中集合初始化(aggregate   initialization)卻變得很方便而且很安全。當產生一個集合物件時,要做的只是指定初始值就行了,然後初始化工作就由編譯器去承擔了。這種指定可以用幾種不同的風格,它取決於正在處理的集合型別。但不管是哪種情況,指定的初值都要用大括號括起來。比如一個內部型別的陣列可以這樣定義:
int   a[5]   =   {   1,   2,   3,   4,   5   };
如果給出的初始化值多於陣列元素的個數,編譯器就會給出一條出錯資訊。但如果給的初始化少於資料元素的個數,那將會怎麼樣呢?例如:
int   b[6]   =   {0};
這時,編譯器會把第一個初始化值賦給陣列的第一個元素,然後用0賦給其餘的元素。注意,如果定義了一個數組而沒有給出一列初始值時,編譯器並不會去做初始化工作。所以上面的表示式是將一個數組初始化為零的簡潔方法,它不需要用一個for迴圈,也避免了“偏移1位”錯誤(它可能比for迴圈更有效,這取決於編譯器)。
陣列還有一種叫自動計數(automatic   counting)的快速初始化方法,就是讓編譯器按初始化值的個數去決定陣列的大小:
int   c[   ]   =   {   1,   2,   3,   4   };
現在,如果決定增加另一個元素到這個陣列上,只要增加一個初始化值即可,如果以此建立我們的程式碼,只需在一處作出修改即可。這樣,在修改時出錯的機會就減少了。但怎樣確定這個陣列的大小呢?用表示式sizeof   c   /   sizeof   *c(整個陣列的大小除以第一個元素的大小)即可算出,這樣,當陣列大小改變時它不需要修改。
for   (   int   i   =   0;   i   <   sizeof   c   /sizeof   *c;   i++)
c[i]++;
因為結構也是一種集合型別,所以它們也可以用同樣的方式初始化。因為C風格的struct的所有成員都是public型的,所以它們的值可以直接指定。
struct   X   {
int   i;
float   f;
char   c;
};
X   x1   =   {   1,   2.2,   ‘c’   };
如果有一個這種struct的陣列,也可以用巢狀的大括號來初始化每一個物件:
X   x2[3]   =   {   {1,   1.1,   ‘a’},   {2,   2.2,   ‘b’}};
這裡,第三個物件被初始化為零。
如果struct中有私有成員(典型的情況就是C++中設計良好的類),或即使所有成員都是公共成員,但有建構函式,情況就不一樣了。在上例中,初始值被直接賦給了集合中的每個元素,但建構函式是通過正式的介面來強制初始化的。這裡,建構函式必須被呼叫來完成初始化,因此,如果有一個下面的struct型別:
struct   Y   {
float   f;
int   i;
Y(int   a);
};
必須指示建構函式呼叫,最好的方法像下面這樣:
Y   y1[   ]   =   {   Y(1),   Y(2),   Y(3)   };
這樣就得到了三個物件和進行了三次建構函式呼叫。只要有建構函式,無論是所有成員都是公共的struct還是一個帶私有成員的class,所有的初始化工作都必須通過建構函式來完成,即使正在對一個集合初始化。
下面是多建構函式引數的又一個例子:
//:   C06:Multiarg.cpp
//   From   Thinking   in   C++,   2nd   Edition
//   Available   at   http://www.BruceEckel.com
//   (c)   Bruce   Eckel   2000
//   Copyright   notice   in   Copyright.txt
//   Multiple   constructor   arguments
//   with   aggregate   initialization
#include   <iostream>
using   namespace   std;

class   Z   {
    int   i,   j;
public:
    Z(int   ii,   int   jj);
    void   print();
};

Z::Z(int   ii,   int   jj)   {
    i   =   ii;
    j   =   jj;
}

void   Z::print()   {
    cout   < <   "i   =   "   < <   i   < <   ",   j   =   "   < <   j   < <   endl;
}

int   main()   {
    Z   zz[]   =   {   Z(1,2),   Z(3,4),   Z(5,6),   Z(7,8)   };
    for(int   i   =   0;   i   <   sizeof   zz   /   sizeof   *zz;   i++)
        zz[i].print();
}   ///:~
注意:這看起來就好象對陣列中的每個物件都呼叫顯式的建構函式。

、、、、、、、、、、、、

/////////////////////////////////////////////////////////

該問題涉及到資料型別初始化的問題,現將C語言中資料型別初始化總結如下

簡單變數的初始化形式如下: 資料型別 變數名=初始化值;
   例如,定義整型變數a,並給其初始化值10的語句如下
   int a=10;

陣列的初始化,需要通過一常量資料列表,對其陣列元素分別進行初始化,形式如下:
  資料型別 陣列名稱〔陣列長度〕={初始化值1,初始化值2,…, 初始化值n};

  例如,定義長度為5的整型陣列,並對其初始化的語句如下:
  int A[5]={20,21,0,3,4};

結構體變數的初始化方式與陣列類似,分別給結構體的成員變數以初始值,而結構體成員變數的初始化遵循簡單變數或陣列的初始化方法。具體的形式如下:
  struct 結構體識別符號
  {
    成員變數列表;
     …
  };
  struct結構體識別符號 變數名={初始化值1,初始化值2,…, 初始化值n };
  例如,定義struct Point型別變數,並初始化的語句如下:
  struct Point oP1={0.0,0.2,0.3};
  struct Point型別變數oP1的三個成員變數的值分別為
  oP1.x=0.0,
  oP1.y=0.2
  oP1.z=0.3
由於定義結構體變數有三種方法,因此初始化結構體變數的方法對應有三種,上面已經介紹了其中的一種形式,其他兩種形式如下:
struct Point
{
  double x;
  double y;
  double z;
} oP1={0.0,0.2,0.3}; struct
{
  double x;
  double y;
  double z;
} oP1={0.0,0.2,0.3};
在初始化結構體變數時候,既可以初始化其全部成員變數,也可以僅僅對其中部分的成員變數進行初始化。例如:
struct Student
{
  long id;
  char name[20];
  char sex;
}a= {0};
其相當於a.id=0;a.name=“”;a.sex=‘/0x0’。
僅僅對其中部分的成員變數進行初始化,要求初始化的資料至少有一個,其他沒有初始化的成員變數由系統完成初始化,為其提供預設的初始化值。各種基本資料型別的成員變數初始化預設值如表9-1所示。

資料型別
預設初始化值
Int                   0
Char                ‘/0x0’
float                0.0
double               0.0
char Array[n]        ”
int Array[n]         {0,0…,0}


對於複雜結構體型別變數的初始化,同樣遵循上述規律,對結構體成員變數分別賦予初始化值。例如:
struct Line
{
int id;
struct Point StartPoint;
struct Point EndPoint;
}oLine1={0,
{0,0,0},
{100,0,0}
};
其中常量0用於初始化oLine1的基本型別成員變數id;常量列表{0,0,0}用於初始化oLine1的struct Point型別成員變數StartPoint;常量列表{100,0,0}用於初始化oLine1的struct Point型別成員變數EndPoint。

最後,總結下結構體初始化常用的2種方法

//////////////////////////////////////////////////////////////////////////////////////////////

struct{  
  //...  
  int   a;  
  int   *p;  
  }x;  

 memset(&x,   0,   sizeof(x))    
  或者  
  memset(&x,   0,   sizeof(struct   A_stru))   
    
 這是結構體變數初始化為0的常見方法,需要注意x前的&號。

///////////////////////////////////////////////////////////////////////////////////////////////////

struct   A   a   =   {0};