日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言 内存分配 地址 指针 数组 参数 解析

發布時間:2023/12/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言 内存分配 地址 指针 数组 参数 解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

指針簡介 : 指針式保存變量地址的變量;

-- 增加閱讀難度 : 指針 和 goto 語句會增加程序的理解難度, 容易出現錯誤;

-- ANSI C : American National Standards Institute 美國國家標準學會, 即標準C;

-- 通用指針類型 : ANSI C中使用 void* 作為通用指針類型, 即指向void的指針, void 是空類型,void* 是空類型指針, 可以指向任意類型的地址;



1. void 與 void*?


(1) void 簡介


void 作用 :?

-- 限定參數: 函數沒有返回值, 需要使用 void 聲明, 否則默認返回 int 類型;

-- 限定返回值 : 函數不接收參數, 使用 void 作為參數, 如果傳入參數, 編譯器就會報錯;


使用void注意點 :?

-- void不能表示變量 : void a, 這樣定義是錯誤的;

-- 默認返回值 : C 中, 如果沒有標明返回值類型, 默認的返回值不是 void, 是 int 類型;

-- void參數 : C 語言中參數是void, 傳入參數不會出錯, C++中傳入參數會出錯, 因此這里我們統一規定, 如果函數沒有參數, 就定義為void;


.


(2) void*簡介


void * 作用 :?

-- 通用數據類型 : void * 指針可以存放任意類型數據的地址, 任何數據類型的指針都可以賦值給 void * 通用類型指針;
-- 任意類型 : 如果 函數 的 參數 和 返回值 可以是任意類型, 就可以使用 void * 作為函數的 參數 或者 返回值;


使用void* 注意點 :?

-- void * 與 其它類型互相賦值 : int * 變量可以賦值給 void * 變量, 但是void * 變量如果賦值給 int * 變量需要強轉為 int * 類型;

-- void * 不允許進行 算數操作 : 標準C 中規定 void * 類型不允許進行 加減乘除 算數運算, 因為我們不知道這個類型的大小, GUN 中void * 等價于 char * ;



2. C 語言 程序內存分配


(1) 內存分區狀況


棧區 (stack) :?

-- 分配, 釋放方式 : 由編譯器自動分配 和 釋放;

-- 存放內容 : 局部變量, 參數;

-- 特點 : 具有 后進先出 特性, 適合用于 保存 回復 現場;


堆區 (heap) :?

-- 分配, 釋放方式 : 由程序員手動 分配(malloc) 和 釋放(free), 如果程序員沒有釋放, 那么程序退出的時候, 會自動釋放;

-- 存放內容 : 存放程序運行中 動態分配 內存的數據;

-- 特點 : 大小不固定, 可能會動態的 放大 或 縮小;


堆區內存申請?:?

-- 申請過程 : OS中有一個記錄空閑內存地址的鏈表, 如果程序員申請內存, 就會找到空間大于申請內存大小的節點, 將該節點從空間內存鏈表中刪除, 并分配該節點;?

-- 剩余內存處理 : 系統會將多余的部分重新放回 空閑內存鏈表中;

-- 首地址記錄大小 : 分配內存的首地址存放該堆的大小, 這樣釋放內存的時候才能正確執行;?


全局區/靜態區 (數據段 data segment /bss segment) :?

-- 分配, 釋放方式 : 編譯器分配內存, 程序退出時系統自動釋放內存;

-- 存放內容: 全局變量, 靜態變量;

-- 特點 : 全局變量 和 靜態變量存儲在一個區域, 初始化的兩種變量 和 未初始化的 存儲在不同區域, 但是兩個區域是相鄰的;


常量區?:?

--?分配, 釋放方式?: 退出程序由系統自動釋放;

--?存放內容?: 常量;


代碼區 (text segment) :?

--分配, 釋放方式 : 編譯器分配內存, 程序退出時系統自動釋放內存;

--存放內容 : 存放 程序的二進制代碼, 和一些特殊常量;


內存存放順序 (由上到下): 棧區 -> 堆區 -> 全局區 -> 常量區 -> 代碼區;


(2) 內存分配方式


全局內存分配 :?

-- 生命周期: 編譯時分配內存, 程序退出后釋放內存, 與 程序 的生命周期相同;

-- 存儲內容 : 全局變量, 靜態變量;


棧內存分配 :

-- 生命周期 : 函數執行時分配內存, 執行結束后釋放內存;

-- 特點 : 該分配運算由處理器處理, 效率高, 但是棧內存控件有限;


堆內存分配 :?

-- 生命周期 : 調用 malloc()開始分配, 調用 free()釋放內存, 完全由程序員控制;

-- 謹慎使用 : 如果分配了 沒有釋放, 會造成內存泄露, 如果頻繁 分配 釋放 會出現內存碎片;?


(3) register變量


使用場景 : 如果 一個變量使用頻率特別高, 可以將這個變量放在 CPU 的寄存器中;

-- 修飾限制 : 只有 局部變量 和 參數 可以被聲明為 register變量, 全局 和 靜態的不可以;

-- 數量限制 : CPU 寄存器 很寶貴, 不能定義太多register變量;


(4) extern 變量


extern變量概念 : 聲明外部變量, 外部變量就是在函數的外部定義的變量, 在本函數中使用;

-- 作用域 : 從外部變量定義的位置開始, 知道本源碼結束都可以使用, 但是只能在定義extern后面使用, 前面的代碼不能使用;

-- 存放位置 : 外部變量 存放在 全局區;


extern變量作用 : 使用extern修飾外部變量, ① 擴展外部變量在本文件中的作用域, ② 將外部變量作用域從一個文件中擴展到工程中的其它文件;


extern聲明外部變量的情況 :?

-- 單個文件內聲明 : 如果不定義在文件開頭, 其作用范圍只能是 定義位置開始, 文件結束位置結束;

-- 多個文件中聲明 : 兩個文件中用到一個外部變量, 只能定義一次, 編譯 和 連接的時候, 如果沒有這個外部變量, 系統會知道這個外部變量在別處定義, 將另一個文件中的外部變量擴展到本文件中;


extern編譯原則:?

-- 本文件中能找到: 編譯器遇到 extern 的時候, 現在本文件中找外部變量的定義的位置, 如果找到, 就將作用域擴展到 定義的位置 知道文件結束;

-- 本文件中找不到 : 如果本文件中找不到, 連接其它文件找外部變量定義, 如果找到, 將外部變量作用域擴展到本文件中;

-- 外部文件找不到 : 報錯;


使用效果 : extern 使用的時候, 可以不帶數據類型;

-- 本文件 : int A = 0; 在第10行, extern A 在第一行, 那么A的作用域就擴展為從第一行到文件末尾;

-- 多文件 : 在任意文件中定義了 int A = 0; 在本文件中聲明 extern A, 那么從當前位置到文件末尾都可以使用該變量;



(5) static變量 與 全局變量區別


static 變量 與 全局變量 相同點 : 全局變量是靜態存儲的, 存儲的方式 和 位置基本相同;


static 變量 與 全局變量不用點 : 全局變量的作用域是 整個項目工程 橫跨過個文件, 靜態變量的作用域是 當前文件, 其它文件中使用是無效的;


變量存儲位置 : 全局變量 和 靜態變量 存放在 全局區/靜態去, 局部變量存放在 棧區(普通變量, 指針變量內容) 和 堆區(指針變量指向的內容);


變量靜態化:?

-- 局部變量 : 局部變量 加上 static , 相當于將局部變量的生命周期擴大到了整個文件, 作用域不改變;

-- 全局變量 : 全局變量 加上 static , 相當于將全局變量的作用域縮小到了單個文件, 生命周期是整個程序的周期;


關于函數頭文件的引申 :?

-- 內部函數 : 單個文件中使用的內部函數, 僅在那個特定文件中定義函數即可;

-- 全局函數 : 如果要在整個工程中使用一個全局函數, 需要將這個函數定義在一個頭文件中;


static變量與普通變量區別 :?

-- static全局變量 與 全局變量區別 : static 全局變量 只初始化一次, 防止在其它文件中使用;

-- static局部變量 與 局部變量區別 : static 局部變量 只初始化一次, 下一次依據上一次結果;


static函數與普通函數區別 : static 函數在內存中只保留一份, 普通函數 每調用一次, 就創建一個副本;

.


(6) 堆 和 棧比較



堆(heap)和棧(stack)區別:?

-- 申請方式 : stack 由系統自動分配, heap 由程序員進行分配;

-- 申請響應 : 如果 stack 沒有足夠的剩余空間, 就會溢出; 堆內存從鏈表中找空閑內存;

-- 內存限制 : stack 內存是連續的, 從高位向低位擴展, 而且很小, 只有幾M, 是事先定好的, 在文件中配置; heap 是不連續的, 從低位向高位擴展, 系統是由鏈表控制空閑程序, 鏈表從低地址到高地址, 堆大小受虛擬內存限制, 一般32位機器有4G heap;

-- 申請效率: stack 由系統分配, 效率高; heap 由程序員分配, 速度慢, 容易產生碎片;


(7) 各區分布情況


.

按照下圖分布 : 由上到下順序 : 棧區(stack) -> 堆區(heap) -> 全局區 -> 字符常量區 -> 代碼區;



驗證分區狀況 :?

-- 示例程序 :?

[cpp] view plain copy print?
  • /*************************************************************************?
  • ????>?File?Name:?memory.c?
  • ????>?Author:?octopus?
  • ????>?Mail:?octopus_work.163.com??
  • ????>?Created?Time:?Mon?10?Mar?2014?08:34:12?PM?CST?
  • ?************************************************************************/??
  • ??
  • #include<stdio.h>??
  • #include<stdlib.h>??
  • ??
  • int?global1?=?0,?global2?=?0,?global3?=?0;??
  • ??
  • void?function(void)??
  • {??
  • ????????int?local4?=?0,?local5?=?0,?local6?=?0;??
  • ????????static?int?static4?=?0,?static5?=?0,?static6?=?0;??
  • ????????int?*p2?=?(int*)malloc(sizeof(int));??
  • ??
  • ????????printf("子函數?局部變量?:?\n");??
  • ????????printf("local4?:?%p?\n",?&local4);??
  • ????????printf("local5?:?%p?\n",?&local5);??
  • ????????printf("local6?:?%p?\n",?&local6);??
  • ??
  • ????????printf("子函數?指針變量?:?\n");??
  • ????????printf("p2?:?%p?\n",?p2);??
  • ??
  • ????????printf("全局變量?:?\n");??
  • ????????printf("global1?:?%p?\n",?&global1);??
  • ????????printf("global2?:?%p?\n",?&global2);??
  • ????????printf("global3?:?%p?\n",?&global3);??
  • ??
  • ????????printf("子函數?靜態變量?:?\n");??
  • ????????printf("static4?:?%p?\n",?&static4);??
  • ????????printf("static5?:?%p?\n",?&static5);??
  • ????????printf("static6?:?%p?\n",?&static6);??
  • ??
  • ????????printf("子函數地址?:?\n");??
  • ????????printf("function?:?%p?\n",?function);??
  • }??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????????int?local1?=?0,?local2?=?0,?local3?=?0;??
  • ????????static?int?static1?=?0,?static2?=?0,?static3?=?0;??
  • ????????int?*p1?=?(int*)malloc(sizeof(int));??
  • ????????const?int?const1?=?0;??
  • ????????char?*char_p?=?"char";??
  • ??
  • ????????printf("主函數?局部變量?:?\n");??
  • ????????printf("local1?:?%p?\n",?&local1);??
  • ????????printf("local2?:?%p?\n",?&local2);??
  • ????????printf("local3?:?%p?\n",?&local3);??
  • ????????printf("const1?:?%p?\n",?&const1);??
  • ??
  • ????????printf("主函數?指針變量?:?\n");??
  • ????????printf("p1?:?%p?\n",?p1);??
  • ??
  • ????????printf("全局變量?:?\n");??
  • ????????printf("global1?:?%p?\n",?&global1);??
  • ????????printf("global2?:?%p?\n",?&global2);??
  • ????????printf("global3?:?%p?\n",?&global3);??
  • ??
  • ????????printf("主函數?靜態變量?:?\n");??
  • ????????printf("static1?:?%p?\n",?&static1);??
  • ????????printf("static2?:?%p?\n",?&static2);??
  • ????????printf("static3?:?%p?\n",?&static3);??
  • ??
  • ????????printf("字符串常量?:?\n");??
  • ????????printf("char_p?:?%p?\n",?char_p);??
  • ??
  • ????????printf("主函數地址?:?\n");??
  • ????????printf("main?:?%p?\n",?main);??
  • ??
  • ??
  • ????????printf("=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?\n");??
  • ??
  • ????????function();??
  • ??
  • ????????return?0;??
  • }??
  • /*************************************************************************> File Name: memory.c> Author: octopus> Mail: octopus_work.163.com > Created Time: Mon 10 Mar 2014 08:34:12 PM CST************************************************************************/#include<stdio.h> #include<stdlib.h>int global1 = 0, global2 = 0, global3 = 0;void function(void) {int local4 = 0, local5 = 0, local6 = 0;static int static4 = 0, static5 = 0, static6 = 0;int *p2 = (int*)malloc(sizeof(int));printf("子函數 局部變量 : \n");printf("local4 : %p \n", &local4);printf("local5 : %p \n", &local5);printf("local6 : %p \n", &local6);printf("子函數 指針變量 : \n");printf("p2 : %p \n", p2);printf("全局變量 : \n");printf("global1 : %p \n", &global1);printf("global2 : %p \n", &global2);printf("global3 : %p \n", &global3);printf("子函數 靜態變量 : \n");printf("static4 : %p \n", &static4);printf("static5 : %p \n", &static5);printf("static6 : %p \n", &static6);printf("子函數地址 : \n");printf("function : %p \n", function); }int main(int argc, char **argv) {int local1 = 0, local2 = 0, local3 = 0;static int static1 = 0, static2 = 0, static3 = 0;int *p1 = (int*)malloc(sizeof(int));const int const1 = 0;char *char_p = "char";printf("主函數 局部變量 : \n");printf("local1 : %p \n", &local1);printf("local2 : %p \n", &local2);printf("local3 : %p \n", &local3);printf("const1 : %p \n", &const1);printf("主函數 指針變量 : \n");printf("p1 : %p \n", p1);printf("全局變量 : \n");printf("global1 : %p \n", &global1);printf("global2 : %p \n", &global2);printf("global3 : %p \n", &global3);printf("主函數 靜態變量 : \n");printf("static1 : %p \n", &static1);printf("static2 : %p \n", &static2);printf("static3 : %p \n", &static3);printf("字符串常量 : \n");printf("char_p : %p \n", char_p);printf("主函數地址 : \n");printf("main : %p \n", main);printf("= = = = = = = = = = = = = = = \n");function();return 0; }
    -- 執行結果 :?

    [cpp] view plain copy print?
  • [root@ip28?pointer]#?gcc?memory.c???
  • [root@ip28?pointer]#?./a.out???
  • 主函數?局部變量?:???
  • local1?:?0x7fff75f5eedc???
  • local2?:?0x7fff75f5eed8???
  • local3?:?0x7fff75f5eed4???
  • const1?:?0x7fff75f5eed0???
  • 主函數?指針變量?:???
  • p1?:?0x19bad010???
  • 全局變量?:???
  • global1?:?0x600e14???
  • global2?:?0x600e18???
  • global3?:?0x600e1c???
  • 主函數?靜態變量?:???
  • static1?:?0x600e34???
  • static2?:?0x600e30???
  • static3?:?0x600e2c???
  • 字符串常量?:???
  • char_p?:?0x4009f7???
  • 主函數地址?:???
  • main?:?0x40065f???
  • =?=?=?=?=?=?=?=?=?=?=?=?=?=?=???
  • 子函數?局部變量?:???
  • local4?:?0x7fff75f5eea4???
  • local5?:?0x7fff75f5eea0???
  • local6?:?0x7fff75f5ee9c???
  • 子函數?指針變量?:???
  • p2?:?0x19bad030???
  • 全局變量?:???
  • global1?:?0x600e14???
  • global2?:?0x600e18???
  • global3?:?0x600e1c???
  • 子函數?靜態變量?:???
  • static4?:?0x600e28???
  • static5?:?0x600e24???
  • static6?:?0x600e20???
  • 子函數地址?:???
  • function?:?0x400528???
  • [root@ip28 pointer]# gcc memory.c [root@ip28 pointer]# ./a.out 主函數 局部變量 : local1 : 0x7fff75f5eedc local2 : 0x7fff75f5eed8 local3 : 0x7fff75f5eed4 const1 : 0x7fff75f5eed0 主函數 指針變量 : p1 : 0x19bad010 全局變量 : global1 : 0x600e14 global2 : 0x600e18 global3 : 0x600e1c 主函數 靜態變量 : static1 : 0x600e34 static2 : 0x600e30 static3 : 0x600e2c 字符串常量 : char_p : 0x4009f7 主函數地址 : main : 0x40065f = = = = = = = = = = = = = = = 子函數 局部變量 : local4 : 0x7fff75f5eea4 local5 : 0x7fff75f5eea0 local6 : 0x7fff75f5ee9c 子函數 指針變量 : p2 : 0x19bad030 全局變量 : global1 : 0x600e14 global2 : 0x600e18 global3 : 0x600e1c 子函數 靜態變量 : static4 : 0x600e28 static5 : 0x600e24 static6 : 0x600e20 子函數地址 : function : 0x400528


    3. 指針與地址



    (1) & 與 * 操作


    取地址運算符 & : p = &c;

    -- 表達式解析 : 將 c 的地址賦值給 變量 p, p 是指向 c 變量的指針;

    -- & 可以使用的情況 : 取地址操作 只能用于內存中的對象, 如變量 或 數組, 棧內存 堆內存 都可以;

    -- & 不適用的情況 : 不能用于 表達式, 常量, register類型變量;?


    間接引用運算符 : * ;

    -- 聲明指針 : int *p ; 該表達式的含義是 *p 的結果是 int 類型, 聲明變量 a, int a, 聲明指針 *p , int *p;

    -- 獲取指針指向的值: int a = *p ;


    (2) 指針定義解析


    聲明指針 和 函數 : int *p, max(int a, int b), 聲明指針變量 語法 與聲明 變量語法類似, 同理聲明函數也一樣;

    -- 原理 : *p 和 max()返回值 類型都是 int 類型;


    指針指向 : 每個指針都必須指向某種特定類型;

    -- 例外: void *p 可以指向任何類型, 但是 p 不能進行取值運算, *p 是錯誤的, 因為不知道 p 指向的數據類型;


    (3) 指針運算及示例


    指針相關運算 : int x = 0; int *p = &x; 那么*p 就可以代表x;

    -- 算數運算 : x = x + 1; 等價于 *p = *p + 1 ; int y = x + 1; 等價于 int y = *p + 1;

    -- 自增運算 : 前提 : ++, * 運算順序是自右向左; ?++*p 和 (*p)++, p 指向的值自增1, 注意要加上括號, 否則會將地址自增;

    -- 指針賦值 : int *p, *q; int a = 0; p = &a; q = p; 最終結果 p 和 q 都指向了 變量 a;


    示例程序 :?

    [cpp] view plain copy print?
  • /*************************************************************************?
  • ????>?File?Name:?pointer_address.c?
  • ????>?Author:?octopus?
  • ????>?Mail:?octopus_work.163.com??
  • ????>?Created?Time:?Mon?10?Mar?2014?09:52:01?PM?CST?
  • ?************************************************************************/??
  • ??
  • #include<stdio.h>??
  • ??
  • int?main(int?argc,?char?**?argv)??
  • {??
  • ????????int?*p,?*q;??
  • ????????int?a?=?10,?b;??
  • ??
  • ????????//p指針指向a變量??
  • ????????p?=?&a;??
  • ??
  • ????????//*p?可以代替?a?進行運算??
  • ????????++*p;??
  • ??
  • ????????b?=?*p?+?5;??
  • ??
  • ????????//指針之間可以直接相互賦值??
  • ????????q?=?p;??
  • ??
  • ????????//打印?p?和?q?指針指向的值??
  • ????????printf("*p?=?%d?\n",?*p);??
  • ????????printf("*q?=?%d?\n",?*q);??
  • ??
  • ??
  • ????????return?0;??
  • }??
  • /*************************************************************************> File Name: pointer_address.c> Author: octopus> Mail: octopus_work.163.com > Created Time: Mon 10 Mar 2014 09:52:01 PM CST************************************************************************/#include<stdio.h>int main(int argc, char ** argv) {int *p, *q;int a = 10, b;//p指針指向a變量p = &a;//*p 可以代替 a 進行運算++*p;b = *p + 5;//指針之間可以直接相互賦值q = p;//打印 p 和 q 指針指向的值printf("*p = %d \n", *p);printf("*q = %d \n", *q);return 0; }
    執行結果 :

    [cpp] view plain copy print?
  • [root@ip28?pointer]#?gcc?pointer_address.c???
  • [root@ip28?pointer]#?./a.out???
  • *p?=?11???
  • *q?=?11???
  • [root@ip28 pointer]# gcc pointer_address.c [root@ip28 pointer]# ./a.out *p = 11 *q = 11

    4. 函數參數的傳值調用和傳址調用


    (1) 傳值調用 和 傳址調用


    傳值調用 : 以傳值的方式將參數傳遞給函數, 不能直接修改主函數中變量的值, 僅僅是將副本傳遞給了函數;


    傳址調用 : 將 變量的指針 傳遞給函數, 當函數對指針進行操作的時候, 主函數中的值也進行了對應變化;


    交換函數示例1?:?

    [cpp] view plain copy print?
  • /*************************************************************************?
  • ????>?File?Name:?swap.c?
  • ????>?Author:?octopus?
  • ????>?Mail:?octopus_work.163.com??
  • ????>?Created?Time:?Mon?10?Mar?2014?11:07:18?PM?CST?
  • ?************************************************************************/??
  • ??
  • #include<stdio.h>??
  • ??
  • void?swap_1(int?a,?int?b)??
  • {??
  • ????????int?temp;??
  • ????????temp?=?a;??
  • ????????a?=?b;??
  • ????????b?=?temp;??
  • ??
  • ????????printf("swap_1?傳值?函數?a?=?%d,?b?=?%d?\n",?a,?b);??
  • }??
  • ??
  • void?swap_2(int?*a,?int?*b)??
  • {??
  • ????????int?temp;??
  • ????????temp?=?*a;??
  • ????????*a?=?*b;??
  • ????????*b?=?temp;??
  • ??
  • ????????printf("swap_2?傳址?函數?a?=?%d,?b?=?%d\n",?*a,?*b);??
  • }??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????????int?a?=?10,?b?=?5;??
  • ??
  • ????????printf("初始值?:?a?=?%d,?b?=?%d?\n\n",?a,?b);??
  • ??
  • ????????swap_1(a,?b);??
  • ????????printf("執行?swap_1?函數,?a?=?%d,?b?=?%d?\n\n",?a,?b);??
  • ??
  • ????????swap_2(&a,?&b);??
  • ????????printf("執行?swap_2?函數,?a?=?%d,?b?=?%d?\n",?a,?b);??
  • ??
  • ??
  • ????????return?0;??
  • }??
  • /*************************************************************************> File Name: swap.c> Author: octopus> Mail: octopus_work.163.com > Created Time: Mon 10 Mar 2014 11:07:18 PM CST************************************************************************/#include<stdio.h>void swap_1(int a, int b) {int temp;temp = a;a = b;b = temp;printf("swap_1 傳值 函數 a = %d, b = %d \n", a, b); }void swap_2(int *a, int *b) {int temp;temp = *a;*a = *b;*b = temp;printf("swap_2 傳址 函數 a = %d, b = %d\n", *a, *b); }int main(int argc, char **argv) {int a = 10, b = 5;printf("初始值 : a = %d, b = %d \n\n", a, b);swap_1(a, b);printf("執行 swap_1 函數, a = %d, b = %d \n\n", a, b);swap_2(&a, &b);printf("執行 swap_2 函數, a = %d, b = %d \n", a, b);return 0; }

    執行結果 :?

    [cpp] view plain copy print?
  • [root@ip28?pointer]#?gcc?swap.c???
  • [root@ip28?pointer]#?./a.out???
  • 初始值?:?a?=?10,?b?=?5???
  • ??
  • swap_1?傳值?函數?a?=?5,?b?=?10???
  • 執行?swap_1?函數,?a?=?10,?b?=?5???
  • ??
  • swap_2?傳址?函數?a?=?5,?b?=?10??
  • 執行?swap_2?函數,?a?=?5,?b?=?10???
  • [root@ip28 pointer]# gcc swap.c [root@ip28 pointer]# ./a.out 初始值 : a = 10, b = 5 swap_1 傳值 函數 a = 5, b = 10 執行 swap_1 函數, a = 10, b = 5 swap_2 傳址 函數 a = 5, b = 10 執行 swap_2 函數, a = 5, b = 10

    示例解析:?

    -- 傳值調用 : swap_1 是傳值調用, 傳入的是 main 函數中的 a b 兩個變量的副本, 因此函數執行完畢后, 主函數中的值是不變的;

    -- 傳址調用 : swap_2 是傳址調用, 傳入的是 a , b 兩個變量的地址 &a, &b, 當在swap_2 中進行修改的時候, 主函數中的 a,b變量也會發生改變;



    (2) 高級示例


    需求分析 : 調用getint()函數, 將輸入的數字字符 轉為一個整形數據;


    getch 和 ungetch 函數 :?

    -- 使用場景 : 當進行輸入的時候, 不能確定是否已經輸入足夠的字符, 需要讀取下一個字符, 進行判斷, 如果多讀取了一個字符, 就需要將這個字符退回去;

    -- 使用效果 : getch() 和 ungetch() 分別是預讀下一個字符, 和 將預讀的字符退回去, 這樣對于其它代碼而言, 沒有任何影響;


    注意的問題 : 出現問題, 暫時編譯不通過, 找個C語言大神解決;


    代碼 :?

    [cpp] view plain copy print?
  • /*************************************************************************?
  • ????>?File?Name:?getint.c?
  • ????>?Author:?octopus?
  • ????>?Mail:?octopus_work.163.com??
  • ????>?Created?Time:?Mon?10?Mar?2014?11:40:19?PM?CST?
  • ?************************************************************************/??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<ctype.h>??
  • #define?SIZE?5??
  • ??
  • int?getint(int?*p)??
  • {??
  • ????//sign?是用來控制數字的正負??
  • ????int?c,?sign;??
  • ??
  • ????//跳過空白字符,?如果是空白字符,?就會進行下一次循環,?直到不是空白字符為止??
  • ??
  • ????while(isspace(c?=?getc(stdin)));??
  • ??
  • ????//如果輸入的字符不是數字,?就將預讀的數據退回到標準輸入流中??
  • ????if(!isdigit(c)?&&?c?!=?EOF?&&?c?!=?'+'?&&?c?!=?'-')??
  • ????{??
  • ????????ungetc(c,?stdin);??
  • ????????return?0;??
  • ????}??
  • ??
  • ????/*?
  • ?????*?如果預讀的是減號,?那么sign?標識就是?-1,??
  • ?????*?如果預讀的是加號,?那么sign?標識就是?1;?
  • ?????*/??
  • ????sign?=?(c?==?'-')???-1?:?1;??
  • ????//如果?c?是?加號?或者?減號,?再預讀一個字符&??
  • ????if(c?==?'+'?||?c?==?'-')??
  • ????????c?=?getc(stdin);??
  • ??
  • ????for(*p?=?0;?isdigit(c);?c?=?getc(stdin))??
  • ????????*p?=?10?*?*p?+?(c?-?'0');??
  • ??
  • ????*p?*=?sign;??
  • ??
  • ????if(c?!=?EOF)??
  • ????????ungetc(c,?stdin);??
  • ??
  • ????return?c;??
  • ??????
  • }??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????int?n,?array[SIZE],?i;???
  • ????for(n?=?0;?n?<?SIZE?&&?getint(&array[n])?!=?EOF;?n++);??
  • ??
  • ????for(i?=?0;?i?<?SIZE;?i++)??
  • ????{??
  • ????????printf("array[%d]?=?%d?\n",?i,?array[i]);??
  • ????}??
  • ????return?0;??
  • }??
  • /*************************************************************************> File Name: getint.c> Author: octopus> Mail: octopus_work.163.com > Created Time: Mon 10 Mar 2014 11:40:19 PM CST************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define SIZE 5int getint(int *p) {//sign 是用來控制數字的正負int c, sign;//跳過空白字符, 如果是空白字符, 就會進行下一次循環, 直到不是空白字符為止while(isspace(c = getc(stdin)));//如果輸入的字符不是數字, 就將預讀的數據退回到標準輸入流中if(!isdigit(c) && c != EOF && c != '+' && c != '-'){ungetc(c, stdin);return 0;}/** 如果預讀的是減號, 那么sign 標識就是 -1, * 如果預讀的是加號, 那么sign 標識就是 1;*/sign = (c == '-') ? -1 : 1;//如果 c 是 加號 或者 減號, 再預讀一個字符&if(c == '+' || c == '-')c = getc(stdin);for(*p = 0; isdigit(c); c = getc(stdin))*p = 10 * *p + (c - '0');*p *= sign;if(c != EOF)ungetc(c, stdin);return c;}int main(int argc, char **argv) {int n, array[SIZE], i; for(n = 0; n < SIZE && getint(&array[n]) != EOF; n++);for(i = 0; i < SIZE; i++){printf("array[%d] = %d \n", i, array[i]);}return 0; }


    執行結果 :?

    [plain] view plain copy print?
  • octopus@octopus-Vostro-270s:~/code/c/pointer$?./a.out???
  • 123??
  • 123?43??
  • 674?1??
  • array[0]?=?123???
  • array[1]?=?123???
  • array[2]?=?43???
  • array[3]?=?674???
  • array[4]?=?1???
  • octopus@octopus-Vostro-270s:~/code/c/pointer$ ./a.out 123 123 43 674 1 array[0] = 123 array[1] = 123 array[2] = 43 array[3] = 674 array[4] = 1



    5. 指針 和 數組



    指針數組比較 :?

    -- 可互相替代 : 數組下標執行的操作都可以使用指針替代;

    -- 效率比較 : 使用指針操作效率比數組要高;


    指針 與 數組初始化 :?

    -- 聲明數組 : int a[10]; 定義一個長度為10 的int數組;

    -- 聲明指針 : int *p; 定義一個指針, 該指針指向整型;

    -- 相互賦值 : p = &a[0], 將數組第一個元素的地址賦值給指針變量;

    -- 使用指針獲取數組對象 : *p 等價于 a[0], *(p + 1) 等價于 a[1], *(p + i)等價于 a[i];

    -- 注意地址的運算 : p + i , 在地址運算上, 每次增加 sizeof(int) * i 個字節;


    將數組賦值給指針的途徑 :?

    -- 將數組第一個元素地址賦值給指針變量 : p = &a[0];

    -- 將數組地址賦值給指針變量 : p = a;


    指針 和 數組 訪問方式互換 : 前提 int *p, a[10]; p = a;

    -- 數組計算方式 : 計算a[i]的時候, 先將數組轉化為 *(a + i)指針, 然后計算該指針值;

    -- 取值等價 : a[i] 等價于 *(p + i);

    -- 地址等價 : &a[i] 與 a + i 是等價的;

    -- 指針下標訪問: p[i] 等價于 *(p + i);

    -- 結論 : 通過數組和下標 實現的操作 都可以使用指針和偏移量進行等價替換;


    指針 和 數組 的不同點 :?

    -- 指針是變量 : int *p, a[10]; p = a 和 p++ 沒有錯誤;

    -- 數組名不是變量 : int *p, a[10]; a = p 和 a++ 會報錯;


    數組參數 :?

    -- 形參指針 : 將數組傳作為參數傳遞給函數的時候, 傳遞的是數組的首地址, 傳遞地址, 形參是指針;


    數組參數示例 :?

    -- 函數參數是數組 : 函數傳入一個字符串數組參數, 返回這個字符串長度;

    [cpp] view plain copy print?
  • /*************************************************************************?
  • ????>?File?Name:?array_param.c?
  • ????>?Author:?octopus?
  • ????>?Mail:?octopus_work.163.com??
  • ????>?Created?Time:?Sat?15?Mar?2014?12:46:57?AM?CST?
  • ?************************************************************************/??
  • ??
  • #include<stdio.h>??
  • ??
  • //計算字符串長度??
  • int?strlen(char?*s)??
  • {??
  • ????????int?n;??
  • ????????for(n?=?0;?*s?!=?'\0';?s++)??
  • ????????????????n++;??
  • ????????return?n;??
  • }??
  • ??
  • int?main(int?argc,?char**?argv)??
  • {??
  • ????????printf("strlen(djdhaj)?=?%d?\n",?strlen("djdhaj"));??
  • ????????printf("strlen(12)?=?%d?\n",?strlen("12"));??
  • ????????printf("strlen(dfe)?=?%d?\n",?strlen("dfe"));??
  • }??
  • /*************************************************************************> File Name: array_param.c> Author: octopus> Mail: octopus_work.163.com > Created Time: Sat 15 Mar 2014 12:46:57 AM CST************************************************************************/#include<stdio.h>//計算字符串長度 int strlen(char *s) {int n;for(n = 0; *s != '\0'; s++)n++;return n; }int main(int argc, char** argv) {printf("strlen(djdhaj) = %d \n", strlen("djdhaj"));printf("strlen(12) = %d \n", strlen("12"));printf("strlen(dfe) = %d \n", strlen("dfe")); }
    -- 執行結果 :?warning: conflicting types for built-in function ‘strlen’, 原因是 C語言中已經有了 strlen 函數了, 如果改一個函數名, 就不會有這個警告了;

    [plain] view plain copy print?
  • [root@ip28?pointer]#?gcc?array_param.c???
  • array_param.c:12:?warning:?conflicting?types?for?built-in?function?‘strlen’??
  • [root@ip28?pointer]#?./a.out?????????????
  • strlen(djdhaj)?=?6???
  • strlen(12)?=?2???
  • strlen(dfe)?=?3???
  • [root@ip28 pointer]# gcc array_param.c array_param.c:12: warning: conflicting types for built-in function ‘strlen’ [root@ip28 pointer]# ./a.out strlen(djdhaj) = 6 strlen(12) = 2 strlen(dfe) = 3

    數組和指針參數 :?將數組名傳給參數, 函數根據情況判斷是作為數組還是作為指針;

    -- 實參 : 指針偏移量 和 數組下標 都可以作為 數組或指針函數形參, 如 數組情況fun(&array[2]) 或者 指針情況fun(p + 2);

    -- 形參 : 函數的形參可以聲明為 fun(int array[]), 或者 fun(int *array), 如果傳入的是數組的第二個元素的地址, 可以使用array[-2]來獲數組取第一個元素;


    數組指針參數示例 :?

    [cpp] view plain copy print?
  • /*************************************************************************?
  • ????>?File?Name:?param_array_pointer.c?
  • ????>?Author:?octopus?
  • ????>?Mail:?octopus_work.163.com??
  • ????>?Created?Time:?Sat?15?Mar?2014?01:28:33?AM?CST?
  • ?************************************************************************/??
  • ??
  • #include<stdio.h>??
  • ??
  • //使用指針做形參?取指針的前兩位?和?當前位??
  • void?fun_p(int?*p)??
  • {??
  • ????????printf("*(p?-?2)?=?%d?\n",?*(p?-?2));??
  • ????????printf("*p?=?%d?\n",?*p);??
  • }??
  • ??
  • //使用數組做形參?取數組的?第-2個元素?和?第0個元素??
  • void?fun_a(int?p[])??
  • {??
  • ????????printf("p[-2]?=?%d?\n",?p[-2]);??
  • ????????printf("p[0]?=?%d?\n",?p[0]);??
  • }??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????????int?array[]?=?{1,2,3,4,5};??
  • ????????//向指針參數函數中傳入指針??
  • ????????printf("fun_p(array?+?2)?:?\n");??
  • ????????fun_p(array?+?2);??
  • ??
  • ????????//向數組參數函數中傳入數組元素地址??
  • ????????printf("fun_a(&array[2])?:?\n");??
  • ????????fun_a(&array[2]);??
  • ??
  • ????????//向指針參數函數中傳入數組元素地址??
  • ????????printf("fun_p(&array[2])?:?\n");??
  • ????????fun_p(&array[2]);??
  • ??
  • ????????//向數組參數函數中傳入指針??
  • ????????printf("fun_a(array?+?2)?:?\n");??
  • ????????fun_a(array?+?2);??
  • ????????return?0;??
  • }??
  • /*************************************************************************> File Name: param_array_pointer.c> Author: octopus> Mail: octopus_work.163.com > Created Time: Sat 15 Mar 2014 01:28:33 AM CST************************************************************************/#include<stdio.h>//使用指針做形參 取指針的前兩位 和 當前位 void fun_p(int *p) {printf("*(p - 2) = %d \n", *(p - 2));printf("*p = %d \n", *p); }//使用數組做形參 取數組的 第-2個元素 和 第0個元素 void fun_a(int p[]) {printf("p[-2] = %d \n", p[-2]);printf("p[0] = %d \n", p[0]); }int main(int argc, char **argv) {int array[] = {1,2,3,4,5};//向指針參數函數中傳入指針printf("fun_p(array + 2) : \n");fun_p(array + 2);//向數組參數函數中傳入數組元素地址printf("fun_a(&array[2]) : \n");fun_a(&array[2]);//向指針參數函數中傳入數組元素地址printf("fun_p(&array[2]) : \n");fun_p(&array[2]);//向數組參數函數中傳入指針printf("fun_a(array + 2) : \n");fun_a(array + 2);return 0; }
    執行效果 :?

    [plain] view plain copy print?
  • [root@ip28?pointer]#?gcc?param_array_pointer.c???
  • [root@ip28?pointer]#?./a.out???
  • fun_p(array?+?2)?:???
  • *(p?-?2)?=?1???
  • *p?=?3???
  • fun_a(&array[2])?:???
  • p[-2]?=?1???
  • p[0]?=?3???
  • fun_p(&array[2])?:???
  • *(p?-?2)?=?1???
  • *p?=?3???
  • fun_a(array?+?2)?:???
  • p[-2]?=?1???
  • p[0]?=?3???
  • [root@ip28 pointer]# gcc param_array_pointer.c [root@ip28 pointer]# ./a.out fun_p(array + 2) : *(p - 2) = 1 *p = 3 fun_a(&array[2]) : p[-2] = 1 p[0] = 3 fun_p(&array[2]) : *(p - 2) = 1 *p = 3 fun_a(array + 2) : p[-2] = 1 p[0] = 3

    總結

    以上是生活随笔為你收集整理的C语言 内存分配 地址 指针 数组 参数 解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。