該文無主要介紹主旨,簡單介紹一些博主在複習c語言中發現的一些易錯點。
memset是計算機中c/c++語言初始化函式。作用是將某一塊記憶體中的內容全部設定為指定的值, 這個函式通常為新申請的記憶體做初始化工作。
#include //需要新增的c庫標頭檔案
void *memset(void *s, int c, size_t n); //函式原型
s 需要填充資料的記憶體的位址
c 填充到記憶體中的新字元
n 需要填充的記憶體大小(位元組為單位)
memset()函式作用是在一段記憶體中填充某個給定的值,函式能給指定記憶體中填充指定的值,但是這裡最常用的是給記憶體清零。主要原因是因為該函式對記憶體進行填充時是按照位元組為單位進行填充的。
下面舉例給某個int陣列填充0和填充1的到的結果:
#include #include int main(int argc, const char *ar**)
putchar('\n');
memset(arr, 1, sizeof(arr))
for (i = 0; i < 5; i++)
putchar('\n');
}
執行程式結果分別是:
0 0 0 0 0
0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
程式成功將0填充到了指定記憶體當中,但是填充1的時候卻失敗了。這裡導致該問題的原因在於memset()函式進行資料填充的時候是按位元組填充的。
這裡我們將arr[0]的資料進行拆解成2進製資料:0x1010101
0000 0001 0000 0001 0000 0001 0000 0001
這裡我們就很容易的發現,函式將1往記憶體中填充的時候是按照位元組來填充的,每個位元組都會填充乙個1,但是int型資料在32位機中是4位元組的,所以這裡就會得到0x1010101的結果。
在這裡我們還要注意乙個問題,就是函式的最後乙個引數,這裡我們需要注意所需填充記憶體大小的計算,由於同種資料型別在不同的作業系統中所佔記憶體不同,所以常用sizeof()函式來輔助我們計算資料所佔記憶體。
在對結構體所佔記憶體進行計算的時候,我們不可避免的需要知道乙個東西,資料對齊方式。資料對齊分為自然對齊和強制對齊兩種方式。 在結構體中的對齊方式是自然對齊:各個型別自然對齊,即其記憶體位址必須是其型別本身的整數倍。結構體對齊到其中成員最大長度型別的整數倍。
以32位系統為例,自然對齊:
char ch ---> 1位元組對齊 sizeof(ch)=1
short s ---> 2位元組對齊 sizeof(s)=2
int i ---> 4位元組對齊 sizeof(i)=4
float f ---> 4 位元組對齊 sizeof(f)=4
double d ---> 4位元組對齊 (系統給它分配兩次空間) sizeof(d)=8;
struct struct1 struct struct2
}
在這裡,struct1所佔記憶體為8位元組,而struct2所佔記憶體為12位元組。
這裡我們計算結構體所佔記憶體時,首先確認其對齊方式,兩個結構體所佔最大記憶體的資料型別是int,所以都是4位元組對齊方式,struct1第乙個資料是int型資料,直接占用4個位元組,第二個資料是char型資料,占用1個位元組,第二個對齊記憶體單元還剩3個位元組,struct1第3個資料是short型資料,占用兩個位元組,而struct1第二個記憶體單元還剩3個位元組,能將其儲存,所以struct1結構體占用8個位元組記憶體。
struct2第乙個資料是char型資料佔據乙個位元組,第乙個對齊單元剩3個位元組,第2個資料是int型資料,4個位元組,第乙個對齊單元剩3個位元組儲存不下去,所以需要新開乙個對齊單元,第3個資料是short型別,佔兩個位元組需要開闢第三個對齊單元,所以struct2結構體占用12個位元組。
|------------------4位元組--------------||------------------4位元組--------------||------------------4位元組--------------|
struct1: |------------------ int --------------|| char short (剩1個位元組)|
struct2: | char (剩3個位元組) ||------------------ int --------------|| short (剩2個位元組) |
c語言中共用體的定義方式與結構體的定義方式基本一致,就是最後乙個大括號後面要加乙個「;」,呼叫方式相同,對記憶體分配上的不同。
共用體中的所有元素都使用同乙個記憶體,且位址相同,所佔記憶體為共用體中所有元素中所佔記憶體最大的資料型別。例如下面這個共用體,其所佔記憶體為4個位元組。每次給c賦值時,會將
union common
;
如下例:
#include #include union common
;int main(int argc, const char *ar**)
且程式執行後的結果為:
0xffffffff
0xffffff01
0xffffffff
我們可以清楚的看到,共用體common中的元素 i 和 c 使用的記憶體都是同一塊,修改 c 的同時,i 也會被修改。修改 i 的時候,c 也會被修改,但是需要注意的是,我們修改其當中元素時,只會對應修改元素所佔的記憶體,超出其記憶體的資料不會受到影響。
這裡我們剛好說一下資料大小端模式的問題,在資料在計算機中儲存的模式分為小端模式和大端模式,小端模式:資料低位元組儲存在記憶體位址小的位置。大端模式:資料高位元組儲存在記憶體位址大的位置。
假設有乙個資料為0x12345678,分別按照大小端模式儲存:
大端模式
小端模式
位址0x00 0x01 0x02 0x03
位址0x00 0x01 0x02 0x03
資料12 34 56 78
資料78 56 34 12
若我們想在程式中實現,剛好可以使用我們上面剛剛舉例的那個共用體,給 c 賦值為1,然後讀取 i 的值,若 i 的值為1,則是小端模式,若 i 的值不為1則為大端模式。
指標陣列和陣列指標我們對其進行區分時只要牢記,指標陣列是個陣列,陣列指標是個指標就容易對其進行區分。下面我們舉兩個例子:
int *p[5] == int *(p[5]) int (*p)[5]
因為 的結合優先順序高於*的結合優先順序,所以int *p[5] == int *(p[5]) ,我們根據其表示式可以看出來,int * 後面接的是乙個陣列,所以 int *p[5]是乙個陣列。該陣列有5個元素,且每個元素都是int *。他是乙個指標陣列。
int (*p)[5] 這裡int *後面接的是乙個變數,而 [5] 則是修飾這個指標指向的元素是乙個有5個元素的陣列。本質是乙個指標。
在這裡我們在講一下 運算子,運算想當與 *();也就是 p[ i ] = *(p + i);
倉促成文,不當之處,尚祈方家和讀者批評指正。聯絡郵箱[email protected]
C語言隨記
1.c11 c語言新標準 2.表示系統自帶的庫,也可寫成 h 表示使用者自定義的庫 3.main函式是c語言的程式入口,現在大多為int main 而不是void main 4.記憶裡的c語言新特性 5.原始檔 通過編輯器建立的檔案,包含源 通常是.c檔案 6.c語言程式 編輯程式 c或.cpp 編...
C語言 C語言之continue
c語言迴圈 c 語言中的continue語句有點像break語句。但它不是跳出該迴圈語句,continue是跳過本次迴圈直接開始下一次迴圈的。在for迴圈裡,continue會跳過本次迴圈,但是自增語句仍然會執行,而在while和do while語句裡嘖是跳過迴圈重新執行判斷語句 課堂作業內容為 輸...
C語言隨記(一) 函式
int argc 該引數必須是整型變數,引數argc中儲存了引數的個數。const char argv 該引數必須是乙個指向組數的陣列指標。argv中argc 0 為自身執行目錄路徑和程式名,argc 1 指向第乙個引數,argc 2 指向第二個引數 main函式是c語言的入口函式,如果需要給mai...