1. 程式人生 > >C語言,指標與記憶體分配

C語言,指標與記憶體分配

指標變數與記憶體分配

1. char * str1;
//str1 只是一個指標,指標指向的空間還沒有分配,所以此時用strcpy向str1所指向的記憶體
中拷貝內容將出錯。利用malloc動態分配指向的記憶體(在堆中):
str1=(char *)malloc(10) or str1=(char *)malloc(sizeof(char) *num)//分配num個char
所佔有的位元組(一般是1個位元組)數空間,用完後必須用free釋放記憶體空間。這與在棧中自動
分配的記憶體不同,棧中的記憶體在函式結束後自動釋放。


2.char str2[10];//字元陣列的賦值要麼在宣告時初始化(="dfdf"or={'a','b','c','d'},要末一個字元的賦值,str[0]= ;str[1]= ;......或者strcpy(str2,"aaaaaa")(因為記憶體空間已分好);
如果char str2[10];str2="abcdefgjk";就會出錯,因為str2表示陣列str2[10]的首地址,在宣告陣列時已經分配好了地址值,不是變數,而是常量。strcpy(str2,"aaaaaa")這種陣列初始化方式,是將"aaaaaa"拷貝到以str2為開始地址的記憶體空間當中。


3。
    char*str1;
    charstr2[10]="dfdf";
       str1=str2;
//將指標str1指向以str2為首地址的記憶體空間,即現在str2和str1表示記憶體中的同一區域.


4。char * str3="aaaaaaaaaaaaaaa";
   char * str2="bbbb";
   strcpy(str3,str2);
//這時的str2和str3就不指向同一記憶體空間,因為str3在初始化時已經分配了指向的記憶體空間;此時只是將str2所指向的記憶體的內容拷貝到str3所指向的記憶體空間的內容(注意:str3指向的記憶體空間的大小最好大於str2所指向的記憶體空間的大小,否則,可能將其他變數的記憶體覆蓋。另外,c語言對陣列不做越界檢查,使用時候小心,否則出現不可預料的錯誤)。


5。其它如int,double,float,short等型別,在申明變數時記憶體空間就已經分配好了。例如:
    inti=1;
    int j;
    j=i;
    j=2;
   printf("i=[%d];j=[%d]\n",i,j);
輸出結果為i=1;j=2


6。面向物件程式設計例如java中的物件宣告,控制代碼和指標的情況類似
    Object myObj= NEW   Object()
   物件控制代碼myObj指向New在記憶體中建立的例項
   聲明瞭物件以後必須例項化,才能呼叫物件的方法。
    ObjectAyouObj=New ObjectA();
   
   myObj=youObj//myObj和youObj同時指向ObjectA的例項

7.圖例:

char*str1="abcd",*str2="cde";//"abcd"的首地址為2000,"cde"的首地址為2004,分別存放在str1和str2.
   
   address(int型別) address(int型別)strings or object

       ------                       ------
str1   |2000|  -----------------2000|   |: memory1
   ------                        ...
str2   |2004|  -----------------2004|   |: memory2
   ------                        ...
       |   |                   2007|    |
   ------                       ------
       |   |                       |    |
   ------                       ------
(1)    str1=str2;         //str1的值變為2004,指向了memory2
(2)   strcpy(str1,str2);//將memory2的內容"cde"拷貝到memory1,str1仍指向memory1
kdsj\0fkdjfkdj\0fkdjfkjdfk\0
               

8.總結:
   記憶體的地址是固定的,而地址所指向的記憶體中的內容是變化的
   指標是存放地址的變數;
   strcpy是記憶體區域中的內容的拷貝,而記憶體的地址是固定不變的。
    字元陣列charstr[10];與 char *str;的區別:
   
   字元陣列在變數宣告時即已分配了記憶體空間,也就是說他的地址已經確定了,而字
   符指標沒有指向記憶體空間(除了char *str="dfdf")。
   字元陣列中str表示陣列的首地址,是一個常量,str等於一個固定的記憶體地址,所
   以永遠不能在等號左邊被賦值(除了宣告變數初始化時,char str[10]="sssssss"),
   只能利用strcpy來改變他所指向的記憶體空間的內容。
   
    而char*str中str是一個變數,可以指向任意記憶體空間,;str=str2只表示將str指向
   地址str2指向的記憶體空間;他同樣必須用strcpy來改變str所指向的記憶體區域的內容。
   注意:指標僅僅起指向的作用!!
   最常見的例子是:
       fgets(str,1000,fp);//預先定義str為字元陣列char str[1000],
   因為不確定檔案的一行有多長
       fetch into :str;//同上

   
9. C語言函式中的區域性變數的空間一般都是放在堆疊裡面.在進入函式前,通過"SUBSP,+XX"來為這些區域性變數分配堆疊空間.然後同樣通過BP來對這些區域性變數進行訪問.函式結束時,"MOVSP,BP"還原堆疊指標,區域性變數隨之而消失.最後以"POP BP"還原BP,結束該函式.

值得注意的是,C語言會自動為C函式中經常使用int型別變數設定成resigterint.這樣的區域性變數就不是使用堆疊空間的了,而就是直接使用SI暫存器.


10.    charstr[10];
    structaa   bb;
   ........
   memset(str,'\0',sizeof(str));//清空記憶體,賦值為10個'\0'字元
   memset(&bb,0,sizeof(struct aa));
   從檔案中逐行讀取,可以處理完一行,memset一下,再讀取下一行
   
     strcat(str1,str2);//也要注意str1最好是定長的陣列,如果是指標還要初始化,還要
長度。
   字串比較大小隻能用strcmp,strncmp
   strcmp(str1,str2)//   =0相等,否則不等
   strncmp(str1,str2,n)//   比較str1和str2的前n個字元
   函式:   
   atoi//將字串轉為整數
    char*itoa(int value, char *string, int radix); //將整數轉為字串


11.注意:char *str1;
    str1=(char*)malloc(sizeof(char) * num)
   給指標分配他所指向的記憶體空間的大小,sizeof函式是取得變數型別或者變數所佔用
   的記憶體位元組數。例如:   
   sizeof(int)//結果為4(個位元組)
       sizeof(double)//結果為8(個位元組)
       char str[]="qqqqqq";sizeof(str)//結果為7(個位元組),不要漏掉'\0'!!!
       char*str="qqqqqq";sizeof(str)//結果為4(個位元組)(32為作業系統),因為str是指標變數!!!
       
注意:指標變數(存放地址的變數)的sizeof值一般都為4,不要將所佔用記憶體大小和字串
      長度混淆!!!
      例如:char str[10]={'a','b','c'};
              strlen(str)//值為3
              sizeof(str)//值為10
              sizeof(char) * strlen(str)//值為3
          
      C語言中陣列定義幾位,元素的最大個數就是幾位。例如char str[10];元素的最大個數
      為10,只不過字元陣列自動在最末尾加'\0',所以定義字元陣列的時候要小心,你想定
      義一個有2個字元的陣列,就要char str[3];,留出一位給'\0',strlen為2,sizeof為
      3!!!!


12. return語句不可返回指向“棧記憶體”的“指標”或者“引用”,因為該記憶體在函式體結束時被
   自動銷燬。但是可以return一個在“棧記憶體”的整型變數,因為返回的是記憶體中的值。
    例如
    char *Func(void)
    {
       char str[] = “helloworld”;    //str的記憶體位於棧上
       .......
       return str;//函式結束時候str為首地址的記憶體即刻釋放,只是返回一個記憶體的地址                 
    }
    main()
   {    char*str1;
       str1=Func;
       printf("%s\n",str);// 將導致錯誤
    
   
13。記憶體分配方式有三種:

(1)靜態記憶體分配。在記憶體的資料區上建立。記憶體在程式編譯的時候就已經分配好。

   這塊記憶體在程式的整個執行期間都存在。例如 已經初始化的變數,全域性變數,static變數。
   
(2)在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式
   執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率
   很高,但是分配的記憶體容量有限。也屬於動態記憶體分配

(3)從堆上分配,亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意多少的記憶體,
程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,
但問題也最多。
按照編譯原理的觀點,程式執行時的記憶體分配有三種策略,分別是靜態的,棧式的,和堆式的.
  靜態儲存分配是指在編譯時就能確定每個資料目標在執行時刻的儲存空間需求,因而在編譯時就可以給他們分配固定的記憶體空間.這種分配策略要求程式程式碼中不允許有可變資料結構(比如可變陣列)的存在,也不允許有巢狀或者遞迴的結構出現,因為它們都會導致編譯程式無法計算準確的儲存空間需求.
  棧式儲存分配也可稱為動態儲存分配,是由一個類似於堆疊的執行棧來實現的.和靜態儲存分配相反,在棧式儲存方案中,程式對資料區的需求在編譯時是完全未知的,只有到執行的時候才能夠知道,但是規定在執行中進入一個程式模組時,必須知道該程式模組所需的資料區大小才能夠為其分配記憶體.和我們在資料結構所熟知的棧一樣,棧式儲存分配按照先進後出的原則進行分配。
  靜態儲存分配要求在編譯時能知道所有變數的儲存要求,棧式儲存分配要求在過程的入口處必須知道所有的儲存要求,而堆式儲存分配則專門負責在編譯時或執行時模組入口處都無法確定儲存要求的資料結構的記憶體分配,比如可變長度串和物件例項.堆由大片的可利用塊或空閒塊組成,堆中的記憶體可以按照任意順序分配和釋放.


    參考:永遠的UNIX高質量C++-C程式設計指南 -- 第7章 記憶體管理 (1)
7.4指標引數是如何傳遞記憶體的?
      如果函式的引數是一個指標,不要指望用該指標去申請動態記憶體。示例7-4-1中,Test函式
      的語句GetMemory(str, 200)並沒有使str獲得期望的記憶體,str依舊是NULL,為什麼?

void GetMemory(char *p, int num)
{
    p = (char*)malloc(sizeof(char) * num);
}
void Test(void)
{
    char *str =NULL;
   GetMemory(str,100);    // str仍然為 NULL
    strcpy(str,"hello");   // 執行錯誤
}

示例7-4-1 試圖用指標引數申請動態記憶體

毛病出在函式GetMemory中。編譯器總是要為函式的每個引數製作臨時副本,指標引數p的副本是 _p,編譯器使 _p=p。如果函式體內的程式修改了_p的內容,就導致引數p的內容作相應的修改。這就是指標可以用作輸出引數的原因。在本例中,_p申請了新的記憶體,只是把_p所指的記憶體地址改變了,但是p絲毫未變。所以函式GetMemory並不能輸出任何東西。事實上,每執行一次GetMemory就會洩露一塊記憶體,因為沒有用free釋放記憶體。
如果非得要用指標引數去申請記憶體,那麼應該改用“指向指標的指標”,見示例7-4-2。

void GetMemory2(char **p, int num)
{
    *p = (char*)malloc(sizeof(char) * num);
}

void Test2(void)
{
    char *str =NULL;
   GetMemory2(&str, 100); // 注意引數是&str,而不是str
    strcpy(str,"hello");  
   cout<< str<< endl;
   free(str);
}

示例7-4-2用指向指標的指標申請動態記憶體

由於“指向指標的指標”這個概念不容易理解,我們可以用函式返回值來傳遞動態記憶體。這種方法更加簡單,見示例7-4-3。

char *GetMemory3(int num)
{
    char *p =(char *)malloc(sizeof(char) * num);
    returnp;
}
void Test3(void)
{
    char *str =NULL;
    str =GetMemory3(100);
    strcpy(str,"hello");
   cout<< str<< endl;
   free(str);
}

示例7-4-3 用函式返回值來傳遞動態記憶體

用函式返回值來傳遞動態記憶體這種方法雖然好用,但是常常有人把return語句用錯了。這裡強調不要用return語句返回指向“棧記憶體”的指標,因為該記憶體在函式結束時自動消亡,見示例7-4-4。
char *GetString(void)
{
    char p[] ="hello world";
    returnp;   // 編譯器將提出警告
}

void Test4(void)
{
char *str = NULL;
str = GetString(); // str 的內容是垃圾
cout<< str<< endl;
}

示例7-4-4 return語句返回指向“棧記憶體”的指標

用偵錯程式逐步跟蹤Test4,發現執行str =GetString語句後str不再是NULL指標,但是str的內容不是“hello world”而是垃圾。
如果把示例7-4-4改寫成示例7-4-5,會怎麼樣?

char *GetString2(void)
{
    char *p ="hello world";
    returnp;
}

void Test5(void)
{
    char *str =NULL;
    str =GetString2();
   cout<< str<< endl;
}

示例7-4-5 return語句返回常量字串

函式Test5執行雖然不會出錯,但是函式GetString2的設計概念卻是錯誤的。因為GetString2內的“helloworld”是常量字串,位於靜態儲存區,它在程式生命期內恆定不變。無論什麼時候呼叫GetString2,它返回的始終是同一個“只讀”的記憶體塊。

14.函式引數的傳遞分為:值傳送和引用(指標)傳送。前者將變數的複本傳給函式的形參,形參的改變不會引起變數原值得改變;後者將變數的地址傳給形參,形參的改變將引起變數的改變。

======================================================================================

2003-3-21 20:29

1.    intfflush(FILE *stream);

清除輸入流的緩衝區,使它仍然開啟,並把輸出流的緩衝區的內容寫入它所聯絡的檔案中。成功時返回0,出錯時返回EOF。
   例如:fflush(stdout);//重新整理螢幕輸出
         FILE *fp;
         fputs(str,fp);
         fflush(fp);//馬上寫入檔案中
       
2.    sprintf(filename,"%s/SFDJERR%s.%d",getenv("PRINTERDIR"),SF_sc.jgbm,SF_sc.wtjg);

3.    void sf_err(struct sf_dktable *sf_dk1,int flag)
      fprintf(fp,"委託機構[%s] 合同號[%s] 銀行帳號[%s] 流水號[%d] 取款金額[.2f] \
      取款成功退款失敗\n",sf_dk1->wtjg,sf_dk1->hth,sf_dk1->zh,sf_dk1->qkwdlsh,\
      sf_dk1->qkje);
      //注意:結構指標的寫法

2003-3-22 9:21

1.再次重申:如果函式的引數是指標,千萬不要用該指標申請動態記憶體。

2003-3-23 17:55
1.   exit退出整個程式;return退出所在的函式

2.    (1)cc-c mm.c
    ar r libmm.amm.o//編譯靜態連線庫,2步走
   靜態連線庫是在編譯的時候將函式庫連線程序序
   如何呼叫靜態連線庫:
       cc -o nn nn.c -L/usr/work/lib -Bstatic -lmm
       //其中-Bstatic可以省略
           
    (2)cc -dy-G -o libmm.so mm.c
    另外,再加上-KPIC後可以提高記憶體的使用率
   //編譯動態連結庫,它是在程式啟動的時候才連線需要的函式
   
   所以利用動態連結庫的程式比靜態連結庫要小得多
   
    需要的環境變數:(注意:不要忘記設)
   LD_LIBRARY_PATH:增加連結程式搜尋路徑。
   LD_RUN_PATH:指定動態連結程式的搜尋路徑。
   例如:LD_LIBRARY_PATH=/usr/work/lib;export LD_LIBRARY_PATH
   
   如何呼叫libmyfun.so:
       cc -o mm mm.c -L/usr/work/lib -Bdynamic -lmyfun
   LD_LIBRARY_PATH必須設定,否則執行mm的時候找不到libmyfun.so!!!
   
   察看程式呼叫了哪些動態連結庫利用ldd:   
       ldd mm   輸出入下:
       dynamic linker: nn: file loaded: /usr/work/zzy/libmyfun.so
       dynamic linker: nn: file loaded: /usr/lib/libc.so.1
       
       
2003-3-24 8:59

1.    char*str1;
    char*str2;
   if(str1==str)//這種寫法正確,它是指str1和str2指向了同一塊記憶體,即地址相等       ...
   
   
    if(strcmp(str1,str2)==0)//它是指str1和str2所指向的記憶體中的內容相等
   
       ...
       
2003-3-31 21:39

1.   全域性變數和靜態全域性變數只能在程式的開始初始化一次。非靜態區域性變數在進入定義
   他們的程式塊的每個入口多次初始化。靜態區域性變數也只初始化一次。
   靜態變數分為:靜態全域性變數和靜態區域性變數
   靜態全域性變數只在他所在的檔案中生存,別的檔案不可以用extern宣告他
   靜態區域性變數只在兩個函式之間跳轉,雖然超過作用域,但是這個變數的生存期為整
    個程式。
   變數的儲存方式;
           extern
           register
           static
           auto
   函式儲存預設為extern   
2.    char*str="abc";
   printf("%d\n",str);//列印地址
   printf("%s\n",str);//列印字串
   
3.? 初始化資料段。通常將此段稱為資料段,它包含了程式中需賦初值的變數。例如, C程
序中任何函式之外的說明:
int maxcount = 99;使此變數以初值存放在初始化資料段中。

一般是:全域性變數和靜態變數
? 非初始化資料段。通常將此段稱為b s s段,這一名稱來源於早期彙編程式的一個操作符,
意思是“block started by symbol(由符號開始的塊)”,在程式開始執行之前,核心將此段初始
化為0。函式外的說明:
long sum[1000] ;
使此變數存放在非初始化資料段中。
? 棧。自動變數以及每次函式呼叫時所需儲存的資訊都存放在此段中。每次函式呼叫時,
其返回地址、以及呼叫者的環境資訊(例如某些機器暫存器)都存放在棧中。然後,新被調
用的函式在棧上為其自動和臨時變數分配儲存空間。通過以這種方式使用棧, C函式可以遞迴
呼叫。
? 堆。通常在堆中進行動態儲存分配。由於歷史上形成的慣例,堆位於非初始化資料段頂
和棧底之間。

    棧

    堆

   未初始化的資料----由exec 賦初值

   初始化的資料------由exec從程式檔案中讀到

   正文--------------由exec從程式檔案中讀到          

注:平常所說的堆疊即為棧(stack)
   
2003-4-2 20:58

1.    函式名:memset
    功 能:設定s中的所有位元組為ch, s陣列的大小由n給定
    用 法: void*memset(void *s, char ch, unsigned n);
   
2.    函式名:memcpy
    功 能:從源source中拷貝n個位元組到目標destin中
    用 法: void*memcpy(void *destin, void *source, unsigned n);
   
   他同strcpy的區別就是memcpy可以給結構賦值:
       struct JieGou jg1;
       struct JieGou jg2;
       memcpy(jg1,jg2,sizeof(struct JieGou));
       
2003-4-24 9:44

1.    char*str1="abcd";
   此時分配的記憶體既不在棧中,也不在堆中,而是在靜態儲存區域。
    charstr2[]="dfdfdf";
   //這是的記憶體在棧中
   
2.   在用delete或用free釋放指標p所指的記憶體後,只是p所指的記憶體釋放了。變數p還是存在的。
   應該馬上顯式地將p置為NULL,
   以防下次使用p時發生錯誤。示例程式如下:if(p==NULL);strcpy(p,"dkfjdf");//
   //p是個野指標,指向了一堆垃圾
“野指標”不是NULL指標,是指向“垃圾”記憶體的指標。人們一般不會錯用NULL指標,
因為用if語句很容易判斷。但是“野指標”是很危險的,if語句對它不起作用。
“野指標”的成因主要有兩種:

(1)指標變數沒有被初始化。任何指標變數剛被建立時不會自動成為NULL指標,它的預設值是隨機的,
它會亂指一氣。所以,指標變數在建立的同時應當被初始化,要麼將指標設定為NULL,要麼讓它指向
合法的記憶體。例如

    char *p =NULL;
    char *str =(char *) malloc(100);

(2)指標p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指標。參見7.5節。

   
3.   不要將BOOL值TRUE和FALSE對應於1和0進行程式設計。大多數程式語言將FALSE定義為0,
   任何非0值都是TRUE。Visual C++將TRUE定義為1,而Visual Basic則將
   TRUE定義為-1。示例程式如下:
   BOOL   flag;
    …
   if(flag)       { // do something}    //正確的用法
   if(flag==TRUE)   { // do something}       // 危險的用法
   if(flag==1)       { // do something}    //危險的用法
   if(!flag)       { // do something}    //正確的用法
   if(flag==FALSE) { // do something}       // 不合理的用法
   if(flag==0)       { // do something}    //不合理的用法

(4)小心不要將"= ="寫成"=",編譯器不會自動發現這種錯誤。
(5)不要將123寫成0123,後者是八進位制的數值。
(6)將自己經常犯的程式設計錯誤記錄下來,製成表格貼在計算機旁邊。

4.   以下是我程式設計時採用的命名約定:
(1)巨集定義用大寫字母加下劃線表示,如MAX_LENGTH;
(2)函式用大寫字母開頭的單詞組合而成,如SetName, GetName ;
(3)指標變數加字首p,如 *pNode ;
(4)BOOL 變數加字首b,如 bFlag ;
(5)int    變數加字首i,如 iWidth ;
(6)float 變數加字首f,如 fWidth ;
(7)double變數加字首d,如 dWidth ;
(8)字串變數加字首str,如 strName ;
(9)列舉變數加字首e,如 eDrawMode ;
(10)類的成員變數加字首m_,如 m_strName, m_iWidth ;
對於 int, float, double 型的變數,如果變數名的含義十分明顯,則不加字首,避免煩瑣。
如用於迴圈的int型變數 i,j,k ;float 型的三維座標(x,y,z)等。


2003-5-13 15:12

1.   傳址引數,交換a,b的值必須用傳址。另外還有傳值,傳引用。
#include <stdio.h>
main()
{
int a=10;
int b=20;
printf("a is %d b is %d\n",a,b);
swap(&a,&b);
printf("a is %d b is %d\n",a,b);
}

swap(int *a,int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}

2003-5-22 17:23

1. 在運用巨集__FILE__和__LINE__時,要注意,不要寫在一個函式裡,在其他地方呼叫此函式
最好寫在如下:
#define ERR  printf("error:[%d]file:[%s]line:[%d]\n",\
sqlca.sqlcode,__FILE__,__LINE__);exit(0);   
如果寫在函式裡,比如:
void err()
{
   printf("error:[%d]file:[%s]line:[%d]\n",sqlca.sqlcode,__FILE__,__LINE__);
}
會造成這樣一種情況:
   __LINE__的值永遠是此函式中printf語句所在的行數
   
2003-5-28 15:30

1.strcpy與memcpy的區別

strcpy(str1,str2)是將str2連帶'\0'一同拷貝到str1,比如:str1="aaaa",str2="bbb",
則結果str1="bbb",導致str1碰到'\0',自動終止字串

memcpy(str1,str2,strlen(str2))是將str2的bbb(不帶'\0')拷貝到str1中,結果為
str1="bbba"

這裡注意:strlen(str2)=3    sizeof(str2)=4  所以如果不想覆蓋str1中其餘的字元,
則不能用sizeof.
strncpy與memcpy功能一樣。
2005-04-12

1.跨平臺申請記憶體
malloc(sizeof(char)*(strlen(str)+1))

char str[]="hello world";
char str1[9]
這兩種情況sizeof(str)=12;sizeof(str1)=9;strlen(str)=11;strlen(str1)=0;
char *p=str;
sizeof (p)=4
如果將str[]用作引數例如fun(char str[100])
則sizeof(str)=4而不是100,因為此時字串陣列自動退化為指標。

2.char *str = "ABCD";
str[0]='M';//將導致錯誤,因為這種方式是在靜態儲存區分配記憶體
如果用strcpy(str,"BBBB")會出錯,因為char *str沒有動態分配記憶體,而是指向

了靜態儲存區如果寫成:char *str = (char *)malloc(100)
strcpy (str,"ABCD");
str[0] = 'M';即可

char str[4] = "ABC";
str[0]='N';
則str = "NBC";因為是在棧上分配記憶體

3.new 必須與delete對應,動態記憶體必須要手工釋放,動態記憶體分配的解構函式只會在使用delete的時候被呼叫。

4.如果檔案中的記錄格式為定長,長度為99,則定義char*strBuf[101]//99+'\n'+'\0';fgets(strBuf,101,fp)從fp中讀取100個字元包括\r,都作為一個字串,最後以'\r'結束(fgets中讀取字串的長度是101-1),這樣輸出到另一個檔案的時候fprint(fp1,"%s",strBuf)自動回車,不用在%s後加\n
如果用fread(strBuf,100,1,fp)這樣的寫法即可。但是之前必須執行

memset(strBuf, '\0',sizeof(strBuf))否則,會出現很亂的字元,而fgets不存在這個問題,不知道為什麼。總之,在使用字串之前,最好memset一下。

無論用fgets還是fread讀取的檔案的記錄結果strlen(strBuf)不是99,而是100。
另外:int fread(void *buf, int size, int count,FILE*stream)表示從檔案中讀取count(欄位數)個欄位,每個欄位大小為size,函式返回實際讀取的欄位數。如果函式要求的欄位數超過實際檔案存放的欄位數,舉例說明:

檔案內容如下:

AAAAAAAAAA
AAAAABBBBB
AAAAA

while(fread(strBuf,11,1,fp))
{
   printf("str=[%s]\n",str);
}

如果用fread讀檔案while(fread(strBuf,11,1,fp))只能讀兩條出來,前兩條返回1,第三條返回0。因為第三條只有6個位元組(連著回車符),不滿足長度為11的條件,所以fread讀檔案的話,最實用於定長檔案。但是第三條fread也將值賦給了strBuf,只是不滿足條件返回了0。第三條的格式:

(1)沒有memset(str,'\0',sizefo(str))

[AAAAA(此處一個回車符)
BBBB(此處一個回車符)--這部分是上一個串留下的部分
]

(2)有memset(str,'\0',sizefo(str))

[AAAAA(此處一個回車符)

]

在例如:

AAAAAAAAAA
AAAAA
AAAAAAAAAA
這種情況會跨行擷取11個位元組,第一條正常,第二條就變為:

[AAAAA(此處是一個回車符)

AAAAA]

如下例所示:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main()
{
int i =0;
FILE *fp,*fp1,*fp2;
char str[10]="370706751";
char str1[11];

memset(str1,'\0',sizeof(str1));
fp = fopen("d:\\test.txt", "w");
if (fp == NULL)
{
   printf("create fileerror!\n");
   return -1;
}
//fwrite("a\0b",3,1,fp);
fprintf(fp, "%s\n\0",str);
//fwrite("a\0b",3,1,fp);
fprintf(fp, "%s\n\0",str);

fclose(fp);

fp1 = fopen("d:\\test.txt", "r");
if (fp1 == NULL)
{
   printf("create fileerror!\n");
   return -1;
}
fp2 = fopen("d:\\test1.txt", "w");
if (fp2 == NULL)
{
   printf("create fileerror!\n");
   return -1;
}
while (fgets(str1,11,fp1) )
//while (fread(str1,10,1,fp1))
{
   i++;
   printf("%s",str1);
   fprintf(fp2,"%s",str1);
}
fclose(fp1);
fclose(fp2);
printf("record num = [%d]\n",i);
}

2005-06-16

c++中

Object object1 = new Object();
......
delete object1;
object1 = NULL;好的程式設計習慣,最後置為NULL,防止野指標,因為雖然記憶體釋放了,但是指向一堆垃圾。

2005-06-18:

int main(int argc , char *arge[])
{
char str[]=" aaaaaaaaa\0bbbbb";
char str1[]=" aaaaaaaaa";

if (memcmp(str,str1,17) == 0)
   printf("xiangdeng\n");

    if(strncmp(str,str1,17) == 0)
   printf("--xiangdeng\n");
}

從上例可以看出strncmp和memcmp的區別,strncmp會截斷字串str與str1判斷,所以輸出相等,但是memcmp會將'\0'帶入比較所以不相等。

同理,strncpy與memcpy的區別也一樣。

int main(int argc , char *arge[])
{
char str[18]=" aaaaaaaaa\0bbbbb";
char str2[18];
strncpy(str2,str,17);
for (int i=0; i<17; i++)
{
   printf("str2[%d]=[%c]\n", i,str2[i]);
}
memcpy(str2,str,17);
for (int i=0; i<17; i++)
{
   printf("str2[%d]=[%c]\n", i,str2[i]);
}
}

memcpy會輸出'\0'後面的bbbbb,而strncpy不會輸出。