带参函数_更好的理解Python第五弹函数预处理与指针
編譯預處理
預處理概念:在編譯之前進行處理
在C語言中,預處理行為宏定義,文件包含,條件編譯
| 指令 | 用處 |
| # | 無 |
| #define | 定義一個宏 |
| #undef? | 取消定義一個已經定義的宏 |
| #include | 包含一個頭/源文件 |
| #if | 若為真,編譯以下代碼 |
| #ifdef | 若宏已定義,則編譯以下代碼 |
| #ifndef | 若宏沒有定義,這編譯以下代碼 |
| #elif | 若前#if為假,此處為真,則編譯以下代碼,相當于elseif |
| #endif | 結束一個#if...#else條件編譯快 |
| #error | 停止編譯并顯示錯誤信息 |
| #line | 強行改變的文件號和行號 |
宏定義:指的是批量處理,即使用簡單的操作來替代復雜的操作,在C語言中,宏定義可以使用一個標識符替代一個字符串
一般形式:
#define?標識符?[(參數)] 字符串優點:方便程序編輯與修改,與使用自定義函數相比,使用宏定義無需“保留函數現場”,可提高運行效率,
缺點:嵌套影響可讀性,帶參定義容易出現參數非法的問題,宏定義不易執行復雜問題。
#include #define x1 3*x*x#define x2(r) (3*(r)*(r)#define?x3?"明天星期幾?"字符串
以0(整數0)結尾的一串字符
0或‘\0’是一樣的,但是和‘0’不同
0標志字符串的結束,但它不是字符串的一部分
計算字符串長度的時候不包含這個0
字符串以數組的形式存在,以數組或指針的形式訪問
更多的是以指針的形式
string.h里有很多處理字符串的函數
指針
計算機系統中運行的程序和數據存儲在計算機內部存儲器中,把存儲器中的一個字節成為一個存儲單元也成內存單元。
內存是由線性連續的存儲單元組成。
C語言中的每一個實體,都要在內存中占有一個可標識的存儲區域,稱為存儲空間
在內存中每一個存儲單元都有一個地址,根據地址可以找到存儲單元的值,將這個地址稱為存儲單元指針,簡稱指針
存儲空間的第一個字節的地址(起始地址,首地址)稱為變量的地址,也稱變量的指針。
指針變量的值是內存中的地址值,那么C語言中的存儲空間`的首地址就可以賦值給指針變量,一個存儲空間的首地址可以稱為該實體的地址,也稱為該實體的指針。由于每個實體都是連續存儲的,當定義了指針變量后,就可以把某個實體的地址賦值給指針變量,然后通過指針變量的值來簡介訪問該實體。
指針可以利用地址,直接指向內存中的任意一個地址,并通過該地址找到地址當中存儲的數據。
指針可以直接修改內存,因此指針的使用時快捷性,高效性,自由的,危險的。
注意:指針不僅可以修改C程序中的數據,更可以修改計算機內存的一切值,在不清楚后果的情況下,這種修改是危險的
?指針可以指向一個變量對應的地址,但不能直接將這個地址按照整數形式賦值給指針變量
%p??//?按照指針形式輸出數據printf("%d",grade)??//輸出grade的值printf("%d",&grade)???//輸出grade的內存地址int?grade?//?grade會被賦值隨機值int?*grade??//會被賦值隨機地址sizeof()???//占空間的字節數指針的定義:
數據類型?*?指針名
int?*?ptr_num,*ptr_Maxfloat * p_averagechar?*?p_ch1,*P_ch2注:在定義時:寫的*是一個說明,標志其后的變量是指針變量,如int * ptr_Max ,ptr_Max是指針名稱
與普通變量一樣,指針先定義,再賦值,再使用,對于指針的賦值,一般理解為指向。
定義指針時的數據類型應當與指針指向的數據類型一致。
指針的初始化:????
指針變量可以初始化一個地址,0或NULL,(指針變量使用過程中必須要有確定的值)
數據類型?*?指針名?=?變量地址如:int?*?point_num =#// &?:地址運算符,取變量的地址// * :指針運算,去指針指向的內存地址中存儲的值// *與&?互為逆運算指針的賦值
將變量所在的地址賦值給指針(直接賦值)
將指針指向的地址賦值給指針(簡介賦值)
指針的運算:
算數運算就是對指針變量加上或減去一個整數,使指針變量指向相鄰的存儲單元。
如果指針運算時指針前帶有*,相當于指針指向的內存地址中存儲的數據參與了運算,即數值相運算。
如果直接用指針參數運算,指針的加,減,代表內存中向高,低地址方向,移動一個指針類型所占據的內存空間。
數據表示兩個指針指向內存之間相隔多少個元素。
指針相減或比較大小時,必須是同一數據類型。
(字符串以“\o”結尾)
說明:
char *pp =str ,相當于指針pp指向了字符串,str的首地址,并非指針pp相當于整個字符串。
運行PP++可以實現指針PP在字符串中指向下一個字符
由于單目運算符的結合律均從右向左,因此*pp++的市級意義為*(PP++),相當于PP++,*?沒有起作用。
同理,++*p相當于++(*p),即指針p指向變量的值自增1,而非指針p向下移動。
指針的比較達標其指向變量的地址的大小比較
地址越靠前越小
取地址預算符&
#include "stdio.h"int main(){????char?c?='A',*p=&c;??//?類型說明符“*”,取地址運算符“&” printf("int c=%d\t char c =%c\t &c=0x%x\n",c,c,&c); printf("int*p =%d\t char*p=%c\t p=%#X\n",*p,*p,p); return 0;}輸出:
int c=65 char c =A &c=0x61ff1bint*p?=65????????char*p=A????????p=0X61FF1B間接訪問運算符“*”
#include "stdio.h"int main(){ int i=37,*p=&i; printf("i=%d,*p=%d\n",i,*p); *p=5; *p*=*p+15; //注意間接訪問符與乘數運算符 printf("i=%d,*p=%d\n",i,*p); return 0;}輸出:
i=37,*p=37i=100,*p=100間接運算符*是一元運算符,也就是說:間接運算符只是一個操作數,
double?x,y,*ptr;?//兩個double變量和一個double指針ptr?=?&x;???//使得ptr指向x的 地址*ptr?=?7.8;??//?*ptr?等效于變量x本身//?注意如果沒有ptr=&x為ptr分配有效地址,那么所包含*ptr的語句都是//?沒有意義的,有可能會趙成程序崩潰。*ptr?*=2.5;??//將x乘以2.5y?=?*ptr?+?0.5??//將加法x+0.5 的結果賦值給y指針與數組
一維數組中的每一個元素都具有相同的數據類型并分配了相同大小的存儲空間,數組元素的地址等于該元素相對數組首地址的偏移量。指針變量既然可以指向變量,當然也可以指向數組元素(把某一元素的地址存放到一個指針變量當中),數組袁術的地址就是數組元素的指針,可以用一個指針變量指向一個數組元素。
int?a[3]?={10,20,30};int *p;p=&a[0];?//把a[0]元素的地址賦值給指針變量,索引一維數組方法:
下標法(即使數組名和下標值),如a[1] 就是用下標法表示數組的第二個元素。
地址法(指針法,位移法):即通過給出地址訪問數據元素,例如:通過a+2地址可以找到素組a第三個元素a[2],
*(a+2)就是a[2].因此,*(a+i)與a[i]等價,都是指數組a的第i+1個元素的值
說明:用下標法訪問數組元素時,是把a[i] 轉化成*(a+i)處理的。即先計算出數組元素的地址(a+i),然后再找到它指向的存儲空間,讀出或寫入它的值。而數組元素用地址法(指針法,位移法)訪問時,則不必每次計算數組元素的地址,特別是使用P++這樣的操作是比較快的(切記注意下標越界)
指針與二維數組:
在C語言中,一維數組名代表了該數組的首地址,也就是該數組的第一個元素的起始地址,它是一個指向數組第一個元素的指針,在一維數組并定義后,編譯系統就會為該數組分配存儲空間,其首地址也就確認了,所以數組名實際上是一個指針常量。
一般形式
[存儲類型]數據類型?(*指針變量名)[數組長度]int?a[4][3]?={{-1,-2,-3},{-4,-5,-6},{-7,-8,-9},{-10,-11,-12}};int?(a*p)[3];//?指針變量q指向一個具有3個int型元素的一維數組q=a;?//把二維數組的首地址給q,p指向二維數組的第一行二維數組a中的元素以下8種方法?
//下標-下標法a[i][j]q[i][j]//下標-位移法*(a[i]+j)*q([i]+j)//位移-下標法(*(a+i))[j](*(q+i))[j]//位移-位移法*(*(a+i))+j)*(*(q+i))+j)指向數組元素的指針變量與指向數組的指針變量的區別
#include "stdio.h"int main(){ int a[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}}; int i,j,count=1,sum=1; int*p=a[0]; //定義 一個int*類型的指針變量p,p是一級指針 int (*q)[3] =a; //指向數組的指針變量q,a是int(*)[3]類型的二級指針 for(;p { printf("%d",*p); } printf("\n------------\n"); for(i=0;i<4;i++){ for(j=0;j<3;j++,count++) { sum=sum+(*(a+i))[j]; if (count%3!=0) printf("a[%d][%d]=%-2d,",i,j,(*(a+i))[j]); //當二級屬為3時,換行 else printf("a[%d][%d]=%d\n",i,j,(*(a+i))[j]); } } for(i=0;j<3;j++){ for (j=0;j<3;j++) { printf("%d+",(*(q+i))[j]); } return 0; }}輸出:
123456789101112------------a[0][0]=1 ,a[0][1]=2 ,a[0][2]=3a[1][0]=4 ,a[1][1]=5 ,a[1][2]=6a[2][0]=7 ,a[2][1]=8 ,a[2][2]=9a[3][0]=10,a[3][1]=11,a[3][2]=12指針與字符串
指向字符串的指針變量
定義char?*?指針變量名1[,....,*指針變量名n]//符號“[]”展示它括起來的內容是可選項初始化char?*?指針變量名1="字符串1"?[,......,*指針變量名n="字符串n"];例如:char * dl = "sunday"上面的語句等價于char * dl;dl="sunday"字符數組的定義
char?數組名1[下標1]?="字符串常量1"[,....,數組n[下標n]="字符串常量n"];例如:char?ch[30]?=?"guangdong China"char?ch[] = "guangdong china"char *ch ="guangdong china"從鍵盤中輸入一個月份號,則程序輸出對應月份的英文名
#include "stdio.h"#include "string.h"char *English_month[]={"illegal month","jannuary","februray","March","April","May","June","July","August","September","October","November","December"};char*month_name(char **q,int n){ if (n<1||n>12) return *q; else return *(q+n);}int main(){ int i; printf("please enter a number of month:"); while (scanf("%d",&i)!=EOF) { printf("It is %s.\n",month_name(English_month,i)); }}指針與函數:
關系
指針作為函數的參數
函數返回值是指針
指向函數的指針
返回指針值的函數
類型標識符?*?函數指針名?(函數參數表)?//?函數參數表 表示函數的形參個書和類型?char * sort(int a[] ,int n);?//此語句定義了一個返回指針值的函數sort(),?//?該函數返回一個字符類型數據的指針,包含兩個形參?//?包含n個元素的字符型數組a,第二個是整型變量n空指針有別于其他指向對象或函數的有效指針,因此,當返回值為指針的函數出現執行失敗的情況時,它通常會使用空指針作為返回值。標準函數fopen()正是這樣的一個例子,如果指定模式下打開某文件失敗使,該函數會返回一個空指針
NULL概念:
數據庫中的NULL表示空,連“\0”都沒有的空
在內存中,NULL代表地址為全0的一個地址,不存儲任何東西。
將定義而未初始化的指針指向NULL,可以有效的防止指針指向未知內存空間而造成的不可預料的錯誤。
string.h
strlen
size_t?strlen(const?char?*s);??//const?不變字符串,返回s的字符串長度(不包括結尾的0)案例:
#include "stdio.h"#include "string.h"int main(int argc,char const *argv[]){ char line[] ="Hello"; printf("strlen=%lu\n",strlen(line));????printf("sizeof=%li\n",sizeof(line));??//?計算了結尾額/0 return 0;}// 輸出:strlen=5sizeof=6strcmp:比較字符串
int?strcmp(const?char*s1,const?char*s2)比較兩個字符串,返回0:s1==s21:?s1?>?s2-1: s1 < s2strcpy
char?*strcpy(char?*restrict?dst,const?char*restrict?src);把src的字符串拷貝到dstrestrict表明src和他不重疊返回dst為了能鏈起代碼來strcat?
char *strcat(char *restrict s1,const char *restrict s2);把s2拷貝到s1的后面,接成一個長的字符串返回s1s1必須具有足夠的空間字符串中找字符char?*strchr(const?char*s,int?c);??//?在前面字符串中找c,忽略大小寫char?*strrchr(const?char?*s,int c);返回NULL表示沒有找指針的應用
//交換兩個變量的值void?swap(int?*pa,int *pb){ int t =*pa; *pa =*pd; *pd=t; }函數返回運算狀態,結果通過指針返回
常見的套路是讓函數返回特殊的不屬于有效范圍內的值來表示出錯
-1或0(在文件操作會看到大量的例子)
但是當任何數值都是有效的結果時,就的分開返回
數組標量是特殊的指針
putchar
int?putchar(int c);向標準輸出寫一個字符返回寫了幾個字符,EOF(-1) 表示寫失敗getchar
int getchar(void);從標準輸入讀入一個字符返回類型是int是為了返回EOF(-1)實例;
#include "stdio.h"int main(int argc,char const *argv[]){ int ch; while ((ch=getchar()) != EOF ){ putchar(ch); } printf("EOF\n"); return 0;}總結
以上是生活随笔為你收集整理的带参函数_更好的理解Python第五弹函数预处理与指针的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: epoll监听文件_【原创】万字长文浅析
- 下一篇: redux异步action_redux-