程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言復習之結構體和指針

C語言復習之結構體和指針

編輯:關於C
一前言:
1>下面所用到的實例為:
typedef  struct {
           int     a;
           short   b[2];
}Ex2;
typedef  struct EX  {
           int   a;
           char  b[3];
           Ex2   c;
           struct  EX  *d;
}EX;
2>類型為EX的結構可以用下面的圖表示:
3>可以用下列的方法進行聲明:
Ex  x = {10,”hi”,{5,{-1,25}},0};
Ex  *px = &x;
二.訪問指針
1.表達式px的右值是:
px是一個指針變量,但此處並不存在任何間接訪問操作符,所以這個表達式的值就是px的內容。
2. 表達式px的左值是
1>它表示了px的舊值將被一個新值所取取代
現在考慮表達式px+1。這個表達式並不是一個合法的左值,因為它的值並不存儲於任何可標識的內存位置。
2>px+1的右值:如果px指向一個結構數組的元素,這個表達式將指向該數組的下一個結構。但,就算如此,這個表達式任然是非法的,因為我們沒有辦法分辨內存下一個位置所存儲的是這些結構元素之一還是其他東西。
三.訪問結構
可以使用*操作符對指針執行間接訪問。
1.表達式*px右值是px所指向的整個結構
間接訪問操作隨箭頭訪問結構,所以使用實現顯示,其結果就是整個結構。
1>你可以把這個表達式賦值給另一個類型相同的結構,2>你也可以把它作為點操作符的左操作數,訪問另一個指定的成員。
3>你可以把它作為參數傳遞給函數,也可以把它作為函數的返回值返回(但是 :這樣做效率不高)
2.表達式*px的左值是:
1>此處,該結構將接受一個新值,或者更准確的說,它將接受它的所有成員的新值。作為左值,重要的是位置,而不是這個位置所保存的值。
2>表達式*px+1是非法的,因為*px的結果是一個結構。C語言沒有定義結構和整型值之間的加法運算。
3>但是*(px+1),如果x是一個數組的元素,這個表達式表示它後面的那個結構。但是,x是一個標量,所以這個表達式實際上是非法的。
四結構的存儲分配
結構在內存中是如何分配呢?
1.編譯器按照成員列表順序一個接一個地給每個成員分配內存。只有當存儲成員時需要滿足正確的邊界對齊要求時,成員之間才可能出現用於填充的額外內存空間。
2.sizeof操作符能夠得出一個結構的整體長度,包括因邊界對齊而跳過的那些字節。
3.如果要確定結構中某個成員的實際位置,可以使用offsetof宏(stddef.h)
offsetof(type,member);
type是結構的類型,member是該結構的成員名,表達式的結構是一個sizeof_t值。表示該指定成員的存數位置(離該結構體存儲的起始位置)
eg:
#include<stdio.h>
#include<stdlib.h>
#include<stddef.h>
struct  tiger {
      char a;
  int  b;
      char c;
};
int  main()
{
       struct  tiger x;
       int  m;
           m = offsetof(struct tiger,b);
       printf(“%d\n”,m);
}
該程序輸出結構為4
五.作為函數參數的結構
結構標量是一個標量,它可以用於其他標量可以使用的任何場合。因此,把結構作為參數傳遞給一個函數是合法的,但這種做法往往不適宜。
1.下面的程序用於操作電子現金收入記錄機。下面是一個結構的聲明。
typedef  struct {
           char  product[PRODUCT_SIZE];
         int   quantity;
           float  unit_price;
           float  total_amount;
}Transaction;
當交易發生時,需要打印收據。
void  print_receipt(Transaction  trans )
{
printf(“%s\n”,trans.product);
printf(“%d @ %2.f \
total %2.f\n”,trans.quantity,trans.unit_price,trans.total_amount)
};
如果current_trans是一個Transaction結構,我們可以像下面這樣調用函數;
print_receipt(current_trans);
說明:
該方法能產生正確的結果,但它的效率很低,因為C語言的參數傳值調用方式要求把參數的一份拷貝傳給函數。如果PRODUCT_SIZE為20,而且在我們使用的機器上整型和浮點型都占4個字節,那麼這個結構將占據32個字節的空間。要把它作為參數進行傳遞,必須把32個字節復制到堆棧中,以後再丟棄。
方法二:
void  print_receipt(Transaction  *trans )
{
printf(“%s\n”,trans.product);
printf(“%d @ %2.f \
total %2.f\n”,trans.quantity,trans.unit_price,trans.total_amount)
};
該函數可以用下面方法進行調用:
print_receipt(&current_trans);
說明:
這次傳遞給函數的是一個指向結構的指針。指針比整個結構要小得多,所以把它壓到堆棧上效率能提高很多。傳遞指針另外需要付出的代價是必須在函數中使用間接訪問來訪問結構的成員。結構越大,把指向它的指針傳遞給函數的效率就越高
向函數傳遞指針的缺陷在於函數現在可以對調用程序的結構變量進行修改。如果不希望如此,可以在函數中使用const關鍵字來防止這類修改。現在通過如下方式進行調用:
void  print_receipt(Transaction  const  *trans);
2.對交易進行處理:計算應該支付的總額。你希望函數comput_total_amount能夠修改結構的total_amount成員。要完成這項任務有三種方法.
1>方法1:
Transaction  compute_total_amount(Transaction  trans)
{
           trans.total_amount = trans.quantity*trans.unit_price;
      return   trans;
}
可以使用下面形式進行調用:
current_trans  = compute_total_amount(current_trans);
結構的一份拷貝作為參數傳遞給函數並被修改。然後一份修改後的結構拷貝從函數返回,所以這個結構被復制了兩次。
2>方法2:
該方法是只返回修改後的值,而不是整個結構
float  compute_total_amount(Transaction  trans)
{
           return   trans.quantity * trans.unit_price;
}
但是,這個函數必須以下面這種方式進行調用:
current_trans.total_amount
=compute_total_amount(current_trans);
此方案比返回整個結構的那個方案強,但這個技巧只適用於計算單個值的情況。如果要求函數修改結構的兩個或更多成員,這樣方法就無能為力了。另外,它仍然存在把整個結構作為參數進行傳遞這個開銷。
3>方法3: www.2cto.com
傳遞一個指針,該方案要好的多
Void compute_toatl_amount(Transaction  *trans)
{
           trans->total_amount =trans->quantity *trans->unit_price;
}
這個函數按照下面的方式進行調用:
compute_total_amount(&current_trans);
說明:
在程序中結構字段total_amount被直接修改,它並不需要把整個結構作為參數傳遞給函數,也不需要把整個修改過的結構作為返回值返回。

摘自 tiger-john
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved