C語言字符型基礎(chǔ)知識
C語言字符型基礎(chǔ)知識
在學(xué)習(xí)中,大家都背過各種知識點吧?知識點在教育實踐中,是指對某一個知識的泛稱。相信很多人都在為知識點發(fā)愁,下面是小編為大家整理的C語言字符型基礎(chǔ)知識,僅供參考,希望能夠幫助到大家。
【資料圖】
C語言字符型基礎(chǔ)知識
1. 字符型數(shù)據(jù)
文字處理是計算機(jī)的一個重要應(yīng)用領(lǐng)域,這個應(yīng)用領(lǐng)域的程序必須能夠使用和處理字符形式的數(shù)據(jù)。在C語言中,字符型數(shù)據(jù)包括字符和字符串兩種,例如"a"是字符,而"Windows" 是字符串。
字符型數(shù)據(jù)在計算機(jī)中存儲的是字符的ASCII碼(ASCII碼表見附錄A),一個字符的存儲占用一個字節(jié)。因為ASCII碼形式上就是0 到255之間的整數(shù),因此C語言中字符型數(shù)據(jù)和整型數(shù)據(jù)可以通用。例如,字符"A"的ASCII碼值用二進(jìn)制數(shù)表示是1000001,用十進(jìn)制數(shù)表示是65,在計算機(jī)中的存儲示意圖見圖3-6。由圖可見,字符"A"的存儲形式實際上就是一個整型數(shù)65,所以它可以直接與整型數(shù)據(jù)進(jìn)行算術(shù)運算、混合運算,可以與整型變量相互賦值,也可以將字符型數(shù)據(jù)以字符或整數(shù)兩種形式輸出。以字符形式輸出時,先將ASCII碼值轉(zhuǎn)換為相應(yīng)的字符,然后再輸出;以整數(shù)形式輸出時,直接將ASCII碼值作為整數(shù)輸出。
2.字符型常量
字符常量亦被稱為字符常數(shù)。C語言中字符常量是括在一對單引號內(nèi)的一個字符。 例如:"x"、"B"、"b"、"$"、"?"、" "(表示空格字符)、"3"都是字符常量,注意其中"B"和"b"是不同的字符常量。
除了以上形式的字符常量外,對于常用的但卻難以用一般形式表示的不可顯示字符,C語言提供了一種特殊的字符常量,即用一個轉(zhuǎn)義標(biāo)識符""開頭,后續(xù)需要的轉(zhuǎn)義字符來表示。常用的轉(zhuǎn)義字符序列的字符常量見表3-4。
轉(zhuǎn)義字符是一種特殊形式的字符常量,其意思是將轉(zhuǎn)義符""后的字符原來的含義進(jìn)行轉(zhuǎn)換,變成某種另外特殊約定的含義。
例如,轉(zhuǎn)義字符" "中的n已不代表字符常量"n",由于n前面是轉(zhuǎn)義符"",所以n就轉(zhuǎn)義成換行。轉(zhuǎn)義字符"15"是"ddd"形式的轉(zhuǎn)義字符,其中"015"是八進(jìn)制字符串,它表示了ASCII碼表中編碼為十進(jìn)制13的字符,也就是回車。轉(zhuǎn)義字符"x1f"是"xdd"形式的轉(zhuǎn)義字符,其中"1f"是十六進(jìn)制字符串,它表示了ASCII碼表中編碼為十進(jìn)制31的字符,也就是▼。
可見,用轉(zhuǎn)義字符方法可以表示任何可顯示或不可顯示的字符。在實際應(yīng)用中,轉(zhuǎn)義字符的使用很多,例如:例3-2中有以下程序行:
printf("a=%f,b=%f ",a,b);
其中的" "就是轉(zhuǎn)義字符換行。幾乎每個程序中都會有一個或若干個這樣的程序行。要注意其使用。
3. 字符型變量
字符型變量用于存放字符常量,即一個字符型變量可存放一個字符,所以一個字符型變量占用1個字節(jié)的內(nèi)存容量。說明字符型變量的關(guān)鍵字是char,使用時只需在說明語句中指明字符型數(shù)據(jù)類型和相應(yīng)的變量名即可。例如:
char s1, s2; /* 說明 s1,s2 為字符型變量 */
s1="A"; /* 為s1賦字符常量"A" */
s2="a"; /*為s2賦字符常量"a" */
4. 字符串常量
字符串常量是用一對雙引號括起來的字符序列。這里的雙引號僅起到字符串常量的邊界符的作用,它并不是字符串常量的一部分。例如下面的字符串都是合法的字符串常量:
"I am a student. ","ABC"," ","a"
注意不要把字符串常量和字符常量混淆,如"a"和"a"是根本不同的數(shù)據(jù),前者是字符串常量,后者是字符常量。如果字符串常數(shù)中出現(xiàn)雙引號,則要用反斜線"""將其轉(zhuǎn)義,取消原有邊界符的功能,使之僅作為雙引號字符起作用。例如,要輸出字符串:
He says:"How do you do."
應(yīng)寫成如下形式:
printf ("He says:"How do you do."");
C語言對字符串常量的長度不加限制,編譯程序總是自動地在字符串的結(jié)尾加上一個轉(zhuǎn)義字符""(即ASCII碼是0,所對應(yīng)的字符是空),作為字符串常量的結(jié)束標(biāo)志。對字符串操作時,這個結(jié)束標(biāo)志是非常重要的。例如輸出字符串時,遇到這個結(jié)束標(biāo)志才終止輸出。
可見,字符常量與字符串常量的區(qū)別有兩個方面:從形式上看,字符常量是用單引號括起的單個字符,而字符串常量是用雙引號括起的一串字符;從存儲方式看,字符常量在內(nèi)存中占一個字節(jié),而字符串常量除了每個字符各占一個字節(jié)外,其字符串結(jié)束符""也要占一個字節(jié)。例如:字符常量"a"占一個字節(jié),而字符串常量"a" 占2個字節(jié),如圖3-7示意圖所示。
C語言沒有專門的字符串變量,如果需要處理字符串,一般用字符型數(shù)組來實現(xiàn)。關(guān)于字符數(shù)組及其它字符數(shù)據(jù)處理問題在本書第八章作詳細(xì)介紹。
5. 字符數(shù)據(jù)的應(yīng)用舉例
例3-3:計算字符"A"與整型數(shù)據(jù)25的和。
/* L3_3.C */
Main()
{ char a; /* 說明a為字符型變量 */
int b; /* 說明b為整型變量 */
a="A"; /* 為a賦字符常量"A" */
b=a+25; /* 計算65+25并賦值給字符變量b */
printf("%c,%d,%c,%d ",a,a,b,b); /* 分別以字符型和整型兩種格式輸出a、b */
}
程序運行的輸出結(jié)果如下:
A,65,Z,90
上述程序中a變量的值是"A",實際存放的是"A"的ASCII碼65,它可直接與十進(jìn)制整型常量25相加,所得整型數(shù)據(jù)90賦值給變量b,而90是大寫字符"Z"的ASCII碼,所以可以將a、b變量分別以字符型和整型兩種格式輸出??梢娮址蛿?shù)據(jù)和整型數(shù)據(jù)是可以通用的。
C語言的最大特點是:功能強(qiáng)、使用方便靈活。
C編譯的程序?qū)φZ法檢查并不象其它高級語言那么嚴(yán)格,這就給編程人員留下“靈活的余地”,但還是由于這個靈活給程序的調(diào)試帶來了許多不便,尤其對初學(xué)C語言的人來說,經(jīng)常會出一些連自己都不知道錯在哪里的錯誤。
1.書寫標(biāo)識符時,忽略了大小寫字母的區(qū)別。
2.忽略了變量的類型,進(jìn)行了不合法的運算。
3.將字符常量與字符串常量混淆。
4.忽略了“=”與“==”的區(qū)別。
5.忘記加分號。分號是C語句中不可缺少的一部分,語句末尾必須有分號。
6.多加分號。 復(fù)合語句的花括號后不應(yīng)再加分號,否則將會畫蛇添足。
7.輸入變量時忘記加地址運算符“&”。
8.輸入數(shù)據(jù)的方式與要求不符。代碼①scanf("%d%d",&a,&b);輸入時,不能用逗號作兩個數(shù)據(jù)間的分隔符②scanf("%d,%d",&a,&b);C規(guī)定:如果在“格式控制”字符串中除了格式說明以外還有其它字符,則在輸入數(shù)據(jù)時應(yīng)輸入與這些字符相同的字符。
9.輸入字符的格式與要求不一致。在用“%c”格式輸入字符時,“空格字符”和“轉(zhuǎn)義字符”都作為有效字符輸入。
10.輸入輸出的數(shù)據(jù)類型與所用格式說明符不一致。
11.輸入數(shù)據(jù)時,企圖規(guī)定精度。
12.switch語句中漏寫break語句。
13.忽視了while和do-while語句在細(xì)節(jié)上的區(qū)別。
14.定義數(shù)組時誤用變量。
15.在定義數(shù)組時,將定義的“元素個數(shù)”誤認(rèn)為是可使的最大下標(biāo)值。
16.初始化數(shù)組時,未使用靜態(tài)存儲。
17.在不應(yīng)加地址運算符&的位置加了地址運算符。
18.同時定義了形參和函數(shù)中的局部變量。
運算符
分為以下幾類:
1、算術(shù)運算符:用于各類數(shù)值運算。包括加(+)、減(-)、乘(*)、除(/)、求余(%)、自增(++)、自減(--)共七種。
2、賦值運算符:用于賦值運算,分為簡單賦值(=)、復(fù)合算術(shù)賦值(+=,-=,*=,/=,%=)和復(fù)合位運算賦值(&=,|=,^=,>>=,<<=)三類共十一種。
3、逗號運算符:用于把若干表達(dá)式組合成一個表達(dá)式(,)。
4、關(guān)系運算符:用于比較運算。包括大于(>)、小于(<)、等于(==)、>=)、小于等于(<=)和不等于(!=)六種。
5、邏輯運算符:用于邏輯運算。包括與(&&)、或(||)、非(!)三種。
6、條件運算符:這是一個三目運算符,用于條件求值(?:)。
7、位操作運算符:參與運算的量,按二進(jìn)制位進(jìn)行運算。包括位與(&)、位或(|)、位非(~)、位異或(^)、左移(<<)、右移(>>)六種。
8、指針運算符:用于取內(nèi)容(*)和取地址(&)二種運算。
9、求字節(jié)數(shù)運算符:用于計算數(shù)據(jù)類型所占的字節(jié)數(shù)(sizeof)。
10、特殊運算符:有括號(),下標(biāo)[],成員(→,.)等幾種。
另外,按參與運算的對象個數(shù),C語言運算符可分為:單目運算符 (如 !)、雙目運算符 (如+,- )和三目運算符 (如 ? : )。
算術(shù)運算符和算術(shù)表達(dá)式
一、基本的算術(shù)運算符
(1)+(加法運算符或正值運算符,如2+5)。
(2)-(減法運算符或負(fù)值運算符,如4-2)。
(3)*(乘法運算符,如3*8)。
(4)/(除法運算符,如11/5)。
/的運算分為兩種情況:
a、“除”的左右兩邊都為整數(shù)時,所得結(jié)果必然是整數(shù)(注意:僅取整數(shù)部分,不是四舍五入)
比如:5/2的值為2,不是2.5,1/2的值為0。
b、“除”的左右兩邊至少有一個是實型數(shù)據(jù)(即小數(shù))時,所得結(jié)果為實型數(shù)據(jù)。
比如:5/2.0的值為2.5,7.0/2.0的值為3.5.
(5)%(模運算符或稱求余運算符,%兩側(cè)均應(yīng)為整型數(shù)據(jù),如9%7的值為2)。
需要說明的是:當(dāng)運算對象為負(fù)數(shù)時,所得結(jié)果隨編譯器不同而不同,在vc中,結(jié)果的符號與被除數(shù)相同,比如:13%-2值為1,而-15%2值為-1。
二、 算術(shù)表達(dá)式和運算符的優(yōu)先級與結(jié)合性
算術(shù)表達(dá)式是用算術(shù)運算符和括號將運算量(也稱操作數(shù))連接起來的、符合C語言語法規(guī)則的表達(dá)式。運算對象包括函數(shù)、常量和變量等。
在計算機(jī)語言中,算術(shù)表達(dá)式的求值規(guī)律與數(shù)學(xué)中的四則運算的規(guī)律類似,其運算規(guī)則和要求如下。
(1)在算術(shù)表達(dá)式中,可使用多層圓括號,但括號必須配對。運算時從內(nèi)層圓括號開始,由內(nèi)向外依次計算各表達(dá)式的值。
(2)在算術(shù)表達(dá)式中,對于不同優(yōu)先級的運算符,可按運算符的優(yōu)先級由高到低進(jìn)行運算,若表達(dá)式中運算符的優(yōu)先級相同,則按運算符的結(jié)合方向進(jìn)行運算。
(3)如果一個運算符兩側(cè)的操作數(shù)類型不同,則先利用自動轉(zhuǎn)換或強(qiáng)制類型轉(zhuǎn)換,使兩者具有相同類型,然后進(jìn)行運算。
三、 自增自減運算符
作用:使變量的值增1或減1。
如:++i,--i (在使用i之前,先使i的值加1、減1)。
i++,i-- (在使用i之后,使i的值加1、減1)。
(1)只有變量才能用自增運算符 (++)和自減運算符(--),而常量或表達(dá)式不能用,如10++或(x+y)++都是不合法的。
(2)++和--的結(jié)合方向是“自右向左“,如 -i++ ,i的左邊是負(fù)號運算符,右邊是自增運算符,負(fù)號運算和自增運算都是 “自右向左“結(jié)合的,相當(dāng)于 -(i++)。
在循環(huán)語句中常用到自增(減)運算符,在指針中也常用到該運算符,考生要弄清楚“i++”和“++i”及“i--”和“--i”的區(qū)別,特別弄清楚表達(dá)式的值和變量的值。
一、位運算符
在計算機(jī)中,數(shù)據(jù)都是以二進(jìn)制數(shù)形式存放的,位運算就是指對存儲單元中二進(jìn)制位的運算。C語言提供6種位運算符。
二、位運算
位運算符 & |~<< >> ∧ 按優(yōu)先級從高到低排列的順序是:
位運算符中求反運算“~“優(yōu)先級最高,而左移和右移相同,居于第二,接下來的順序是按位與 “&“、按位異或 “∧“和按位或 “|“。順序為~ << >> & ∧ | 。
例1:左移運算符“<<”是雙目運算符。其功能把“<< ”左邊的運算數(shù)的各二進(jìn)位全部左移若干位,由“<<”右邊的數(shù)指定移動的位數(shù),高位丟棄,低位補(bǔ)0。
例如:
a<<4
指把a(bǔ)的各二進(jìn)位向左移動4位。如a=00000011(十進(jìn)制3),左移4位后為00110000(十進(jìn)制48)。
例2:右移運算符“>>”是雙目運算符。其功能是把“>> ”左邊的運算數(shù)的各二進(jìn)位全部右移若干位,“>>”右邊的數(shù)指定移動的位數(shù)。
例如:
設(shè) a=15,
a>>2
表示把000001111右移為00000011(十進(jìn)制3)。
應(yīng)該說明的是,對于有符號數(shù),在右移時,符號位將隨同移動。當(dāng)為正數(shù)時,最高位補(bǔ)0,而為負(fù)數(shù)時,符號位為1,最高位是補(bǔ)0或是補(bǔ)1 取決于編譯系統(tǒng)的規(guī)定。
例3:設(shè)二進(jìn)制數(shù)a是00101101 ,若通過異或運算a∧b 使a的高4位取反,低4位不變,則二進(jìn)制數(shù)b是。
解析:異或運算常用來使特定位翻轉(zhuǎn),只要使需翻轉(zhuǎn)的位與1進(jìn)行異或操作就可以了,因為原數(shù)中值為1的位與1進(jìn)行異或運算得0 ,原數(shù)中值為0的位與1進(jìn)行異或運算結(jié)果得1。而與0進(jìn)行異或的位將保持原值。異或運算還可用來交換兩個值,不用臨時變量。
如 int a=3 , b=4;,想將a與b的值互換,可用如下語句實現(xiàn):
a=a∧b;
b=b∧a;
a=a∧b;
所以本題的答案為: 11110000 。
C語言中標(biāo)識符的命名規(guī)則如下:
標(biāo)識符只能由字母、數(shù)字、下劃線組成;
標(biāo)識符的第一個字母必須是字母和下劃線;
標(biāo)識符區(qū)分大小寫字母,如If和if是兩個完全不同的標(biāo)識符。
合法標(biāo)識符如下:
A6, b_3 , _mn
非法的標(biāo)識符如下:
ab#12 , 8m , tr3:4 , yes no
標(biāo)識符不能與程序中具有特殊意義的關(guān)鍵字相同,不能與用戶編制的函數(shù)名、C語言庫函數(shù)相同,在程序中各種標(biāo)識符盡量不要重復(fù),以便區(qū)分。選擇變量名和其他標(biāo)識符時,應(yīng)注意做到 “見名知義”。
標(biāo)識符分為如下三類:
1、關(guān)鍵字
關(guān)鍵字是具有特定含義的,專門用來說明c語言特定成分的一類標(biāo)識符,不能用作用戶的標(biāo)識符。
auto
break
case
char
union
do
double
else
enum
extern
goto
if
int
long
short
signed
static
sizof
struct
switch
unsigned
void
for
while
typedef
continue
float
return
typedef
default
2、預(yù)定義標(biāo)識符
預(yù)定義標(biāo)識符在c語言中也有特定的含義,但可以用作用戶標(biāo)識符,預(yù)定義標(biāo)識符分為兩類:
(1)、庫函數(shù)名字,比如(printf,scanf,sin,isdigit等)
(2)、編譯處理命令名,比如(define,include)
3、用戶標(biāo)識符
用戶根據(jù)需要自己定義的標(biāo)識符稱為用戶標(biāo)識符。無論如何自定義標(biāo)識符,都必須符合標(biāo)識符的三條命名規(guī)則。
C語言
char *strchr(const char* _Str,int _Val)
char *strchr(char* _Str,int _Ch)
頭文件:#include
功能:查找字符串s中首次出現(xiàn)字符c的位置
說明:返回首次出現(xiàn)c的位置的指針,返回的地址是被查找字符串指針開始的第一個與Val相同字符的指針,如果s中不存在c則返回NULL。
返回值:成功則返回要查找字符第一次出現(xiàn)的位置,失敗返回NULL
參數(shù)編輯
haystack
輸入字符串。
needle
如果 needle 不是一個字符串,那么它將被轉(zhuǎn)化為整型并且作為字符的序號來使用。
before_needle
若為 TRUE,strstr() 將返回 needle 在 haystack 中的位置之前的部分。
返回: 返回字符串的一部分或者 FALSE(如果未發(fā)現(xiàn) needle)。
例子:
1
2
3
4
5
6
7
$email="name@example.com";
$domain=strchr($email,"@");
echo$domain;//打印@example.com
$user=strchr($email,"@",true);//從PHP5.3.0起
echo$user;//打印name
?>
函數(shù)公式編輯
實現(xiàn):
1
2
3
4
5
6
7
8
char*strchr(char*s,charc)
{
while(*s!=""&&*s!=c)
{
++s;
}
return*s==c?s:NULL;
}
范例
舉例1:(在Visual C++ 6.0中運行通過)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include
#include
int main(void)
{
char string[17];
char *ptr,c="r";
strcpy(string,"Thisisastring");
ptr=strchr(string,c);
if(ptr)
printf("Thecharacter%cisatposition:%s ",c,ptr);
else
printf("Thecharacterwasnotfound ");
return0;
}
運行結(jié)果:
The character r is at position: ring
請按任意鍵繼續(xù). . .
舉例2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// strchr.c
#include
#include
int main()
{
char temp[32];
memset(temp,0,sizeof(temp));
strcpy(temp,"Golden Global View");
char *s = temp;
char *p,c="v";
p=strchr(s,c);
if(p)
printf("%s",p);
else
printf("Not Found!"); return 0;
}
運行結(jié)果:Not Found!Press any key to continue
舉例3:
1
2
3
4
5
6
7
8
9
10
11
#include
#include
void main()
{
char answer[100],*p;
printf("Type something: ");
fgets(answer,sizeof answer,stdin);
if((p = strchr(answer," ")) != NULL)
*p = "";//手動將 位置處的值變?yōu)?
printf("You typed "%s" ",answer);
}
fgets不會像gets那樣自動地去掉結(jié)尾的 ,所以程序中手動將 位置處的值變?yōu)?代表輸入的結(jié)束。
函數(shù)說明
語法
指針名=(數(shù)據(jù)類型*)realloc(要改變內(nèi)存大小的指針名,新的大小)。
新的大小可大可小(但是要注意,如果新的大小小于原內(nèi)存大小,可能會導(dǎo)致數(shù)據(jù)丟失,慎用!)
頭文件
#include
功能
先判斷當(dāng)前的指針是否有足夠的連續(xù)空間,如果有,擴(kuò)大mem_address指向的地址,并且將mem_address返回,如果空間不夠,先按照newsize指定的大小分配空間,將原有數(shù)據(jù)從頭到尾拷貝到新分配的內(nèi)存區(qū)域,而后釋放原來mem_address所指內(nèi)存區(qū)域(注意:原來指針是自動釋放,不需要使用free),同時返回新分配的內(nèi)存區(qū)域的首地址。即重新分配存儲器塊的地址。
返回值
如果重新分配成功則返回指向被分配內(nèi)存的指針,否則返回空指針NULL。
注意
當(dāng)內(nèi)存不再使用時,應(yīng)使用free()函數(shù)將內(nèi)存塊釋放。
相關(guān)函數(shù)
1
malloc、calloc、free、_alloca
應(yīng)用舉例
舉例1
從這個例子可以看出realloc函數(shù)的功能。
運行環(huán)境:ubuntu 12.04 GCC 4.6.3
運行結(jié)果:
malloc 0x904f008
realloc 0x904f008
0 1 2 3 4 5 6 7 8 9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include
#include
int main()
{
inti;
int*pn=(int*)malloc(5*sizeof(int));
printf("malloc%p ",pn);
for(i=0;i<5;i++)
pn[i]=i;
pn=(int*)realloc(pn,10*sizeof(int));
printf("realloc%p ",pn);
for(i=5;i<10;i++)
pn[i]=i;
for(i=0;i<10;i++)
printf("%3d",pn[i]);
free(pn);
return 0;
}
舉例2
:(在TC2.0中運行通過)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//realloc.c
#include
#include
main()
{
char*p;
clrscr();//clearscreen
p=(char*)malloc(100);
if(p)
printf("MemoryAllocatedat:%x",p);
else
printf("NotEnoughMemory! ");
get);
p=(char*)realloc(p,256);
if(p)
printf("MemoryReallocatedat:%x",p);
else
printf("NotEnoughMemory! ");
free(p);
get);
return 0;
}
內(nèi)存分配編輯
如果有足夠空間用于擴(kuò)大mem_address指向的內(nèi)存塊,則分配額外內(nèi)存,并返回mem_address。
這里說的是“擴(kuò)大”,我們知道,realloc是從堆上分配內(nèi)存的,當(dāng)擴(kuò)大一塊內(nèi)存空間時, realloc()試圖直接從堆上現(xiàn)存的數(shù)據(jù)后面的那些字節(jié)中獲得附加的字節(jié),如果能夠滿足,自然天下太平。也就是說,如果原先的`內(nèi)存大小后面還有足夠的空閑空間用來分配,加上原來的空間大小= newsize。那么就ok。得到的是一塊連續(xù)的內(nèi)存。
如果原先的內(nèi)存大小后面沒有足夠的空閑空間用來分配,那么從堆中另外找一塊newsize大小的內(nèi)存。
并把原來大小內(nèi)存空間中的內(nèi)容復(fù)制到newsize中。返回新的mem_address指針。(數(shù)據(jù)被移動了)。
老塊被放回堆上。
例如
1
2
3
4
5
6
7
8
9
#include
voidmain()
{
char*p,*q;
p=(char*)malloc(10);
q=p;
p=(char*)realloc(q,20);//A行,通過realloc擴(kuò)大p的空間,并把新的地址賦值給p。
//…………………………
}
在這段程序中我們增加了指針q,用它記錄了原來的內(nèi)存地址p。這段程序可以編譯通過,但在執(zhí)行到A行時,如果原有內(nèi)存后面沒有足夠空間將原有空間擴(kuò)展成一個連續(xù)的新大小的話,realloc函數(shù)就會以第二種方式分配內(nèi)存,此時數(shù)據(jù)發(fā)生了移動,那么所記錄的原來的內(nèi)存地址q所指向的內(nèi)存空間實際上已經(jīng)放回到堆上了!這樣就會產(chǎn)生q指針的指針懸掛,即指針指向了一塊沒有分配給用戶使用的內(nèi)存,如果再用q指針進(jìn)行操作就可能發(fā)生意想不到的問題。所以在應(yīng)用realloc函數(shù)是應(yīng)當(dāng)格外注意這種情況。
返回情況
返回的是一個void類型的指針:調(diào)用成功。(這就要求在你需要的時候進(jìn)行強(qiáng)制類型轉(zhuǎn)換)
返回NULL:當(dāng)需要擴(kuò)展的大小(第二個參數(shù))為0并且第一個參數(shù)不為NULL時。此時原內(nèi)存變成“free(游離)”的了。
返回NULL:當(dāng)沒有足夠的空間可供擴(kuò)展的時候。此時,原內(nèi)存空間的大小維持不變。
特殊情況
如果mem_address為NULL,則realloc()和malloc()類似。分配一個newsize的內(nèi)存塊,返回一個指向該內(nèi)存塊的指針。
如果newsize大小為0,那么釋放mem_address指向的內(nèi)存,并返回NULL。
如果沒有足夠可用的內(nèi)存用來完成重新分配(擴(kuò)大原來的內(nèi)存塊或者分配新的內(nèi)存塊),則返回NULL。而原來的內(nèi)存塊保持不變。
現(xiàn)存的數(shù)據(jù)然后就被拷貝至新的位置,而老塊則放回到堆上.重要的信息就是數(shù)據(jù)可能被移動
#include
#include
int main(int argc, char* argv[])
{
char *p,*q;
p = (char *)malloc(10);
q = p;
p = (char *)realloc(p,10);
printf("p=0x%x/n",p);
printf("q=0x%x/n",q);
return 0;
}
輸出結(jié)果:realloc后,內(nèi)存地址不變
p=0x431a70
q=0x431a70
例2:
#include
#include
int main(int argc, char* argv[])
{
char *p,*q;
p = (char *)malloc(10);
q = p;
p = (char *)realloc(p,1000);
printf("p=0x%x/n",p);
printf("q=0x%x/n",q);
return 0;
}
輸出結(jié)果:realloc后,內(nèi)存地址發(fā)生了變化
p=0x351c0
q=0x431a70
例
1 #include
2 #include
3 #include
4
5 int main(int argc, char **argv){
6
7 char *p, *p2, *pnew;
8 int offset = 0;
9
10 p = (char *)malloc(10);
11 if(!p){
12 printf("malloc p error ");
13 }
14 strcpy(p, "Hello,");
15 p2 = strchr(p,",");
16 offset = p2-p+1;
17
18 pnew = (char *)realloc((void *)p, 20);
19
20 if(pnew){
21 p = pnew;
22 p2 = pnew + offset;
23 strcpy(p2," world");
24 }
25 printf("string is: %s ",p);
26 return 0;
27 }
執(zhí)行結(jié)果:string is: Hello, world
使用總結(jié)
1. realloc失敗的時候,返回NULL
2. realloc失敗的時候,原來的內(nèi)存不改變,不會釋放也不會移動
3. 假如原來的內(nèi)存后面還有足夠多剩余內(nèi)存的話,realloc的內(nèi)存=原來的內(nèi)存+剩余內(nèi)存,realloc還是返回原來內(nèi)存的地址; 假如原來的內(nèi)存后面沒有足夠多剩余內(nèi)存的話,realloc將申請新的內(nèi)存,然后把原來的內(nèi)存數(shù)據(jù)拷貝到新內(nèi)存里,原來的內(nèi)存將被free掉,realloc返回新內(nèi)存的地址
4. 如果size為0,效果等同于free()。這里需要注意的是只對指針本身進(jìn)行釋放,例如對二維指針**a,對a調(diào)用realloc時只會釋放一維,使用時謹(jǐn)防內(nèi)存泄露。
5. 傳遞給realloc的指針必須是先前通過malloc(), calloc(), 或realloc()分配的
6.傳遞給realloc的指針可以為空,等同于malloc。
1.什么是進(jìn)制
進(jìn)制是一種計數(shù)的方式,常用的有二進(jìn)制、八進(jìn)制、十進(jìn)制、十六進(jìn)制。任何數(shù)據(jù)在計算機(jī)內(nèi)存中都是以二進(jìn)制的形式存放的。
我對進(jìn)制的個人理解,二進(jìn)制數(shù)是以2為計算單元,滿2進(jìn)1位的數(shù);八進(jìn)制數(shù)是以8為計算單元,滿8進(jìn)1位的數(shù)。
對于任何一個數(shù)字,我們都可以用不同的進(jìn)制來表示,比如,十進(jìn)制數(shù)12,用二進(jìn)制表示為1100,用八進(jìn)制表示為14,用十六進(jìn)制表示為0xC。
2.進(jìn)制的轉(zhuǎn)換規(guī)則
遵循滿進(jìn)制值進(jìn)1位,個位數(shù)變?yōu)?的原理,下面我們以十進(jìn)制數(shù)18為例,對1-18中每一個數(shù)值轉(zhuǎn)換各種進(jìn)制做一個詳細(xì)說明
轉(zhuǎn)二進(jìn)制:
①小于2,無需進(jìn)1位,1的二進(jìn)制值是1
②為二進(jìn)制值1后面一個數(shù),由于1+1滿2,需要進(jìn)1位,個位數(shù)變?yōu)?,所以2的二進(jìn)制值是10
③為二進(jìn)制值10后面一個數(shù),由于11的個位數(shù)1小于2,無需進(jìn)1位,所以3的二進(jìn)制值是11
④為二進(jìn)制值11后面一個數(shù),由于11的個位數(shù)1+1滿2,需要進(jìn)1位,而二進(jìn)制值11的位數(shù)1+1又滿2,所以位數(shù)加1,最終轉(zhuǎn)換結(jié)果為100
轉(zhuǎn)換思路:
二進(jìn)制值11+1 ->10+(1+1)(個位等于2,進(jìn)1位,個位數(shù)變?yōu)?) ->(1+1)+0(位數(shù)滿2,進(jìn)1位) -> 100
以此類推,最終十進(jìn)制數(shù)18的二進(jìn)制轉(zhuǎn)換結(jié)果是10010
轉(zhuǎn)八進(jìn)制:
1-7小于8,無需進(jìn)1位,1-7的八進(jìn)制由1-7表示
8為八進(jìn)制值7后面一個數(shù),由于7+1滿8,需要進(jìn)1位,個位數(shù)變?yōu)?,所以8的八進(jìn)制值是10
以此類推,最終十進(jìn)制數(shù)18的八進(jìn)制轉(zhuǎn)換結(jié)果是22
轉(zhuǎn)十六進(jìn)制:
十六進(jìn)制中,個位數(shù)1-15分別為1 2 3 4 5 6 7 8 9 a b c d e f (a=10....f=15)
16為十六進(jìn)制值c后面1個數(shù),由于c+1滿16,需要進(jìn)1位,個位數(shù)變?yōu)?,所以16的十六進(jìn)制是10。
最終十進(jìn)制數(shù)18的十六進(jìn)制轉(zhuǎn)換結(jié)果是12
詳細(xì)結(jié)果如下圖所示(C語言把數(shù)字前面加0x的數(shù)認(rèn)為是十六進(jìn)制數(shù))
3.C語言中int類型進(jìn)制的聲明以及占位符
雖然以下3個變量的賦值方式不同,但實際賦值結(jié)果都是18
//二進(jìn)制類型數(shù)字加0b
int number1 = 0b10010;
//八進(jìn)制類型數(shù)字加0
int number2 = 022;
//十六進(jìn)制類型數(shù)字加0x
int number3 = 0x12;
八進(jìn)制占位符:%o
十六進(jìn)制占位符:%x
4.內(nèi)存存儲數(shù)據(jù)細(xì)節(jié)
我們知道,int類型數(shù)據(jù)占據(jù)4個字節(jié),1個字節(jié)是8bit。并且任何數(shù)據(jù)在計算機(jī)內(nèi)存中都是以二進(jìn)制的形式存放的,所以內(nèi)存需要用32個0或1來描述1個int類型數(shù)據(jù)。
由于18的二進(jìn)制數(shù)是10010,我們將一個int類型變量賦值18,本質(zhì)上是將這個變量的內(nèi)存地址對應(yīng)的32個bit位修改為:
0000 0000 0000 0000 0000 0000 0001 0010(未滿31位,后面的數(shù)字用0填充:為什么是31而不是32呢,后面會介紹)
假設(shè)我們定義兩個變量
int number1 = 12; int number2 = 13;
計算機(jī)會根據(jù)內(nèi)存地址以由大到小的順序進(jìn)行分配內(nèi)存空間,具體如下圖所示:
5.進(jìn)制的轉(zhuǎn)換公式
二進(jìn)制轉(zhuǎn)十進(jìn)制
0b1100 ->0*2的0次方 + 0*2的1次方 + 1*2的2次方 + 1*2的3次方 = 12
十進(jìn)制轉(zhuǎn)二進(jìn)制
67 ->64+2+1 ->2的6次方+ 2的1次方 + 2的0次方 = 0b1000011
6.進(jìn)制的其他知識
①.n位二進(jìn)制能保存的整數(shù)范圍公式:2的n次方-1
例如,3位的二進(jìn)制數(shù)最大值為111,對應(yīng)的十進(jìn)制數(shù)字為7;5位的二進(jìn)制數(shù)最大值為11111,對應(yīng)的十進(jìn)制數(shù)字為(2*2*2*2*2)-1 = 31。
②.負(fù)數(shù)的二進(jìn)制保存規(guī)則是最左邊的數(shù)字是1。例如,0000 0000 0000 0000 0000 0000 0001 0010 表示正整數(shù),1111 1111 1111 1111 1111 1111 1110 1101表示負(fù)數(shù)
由此,我們就能推測出,int類型能保存的最大整數(shù)是2的(32-1)次方-1 = 2147483647。為什么要用32-1,很簡單,32個bit中,必須抽1個bit位用來描述這個數(shù)字是正數(shù)還是負(fù)數(shù)。
C語言函數(shù)
包含文件:string.h
函數(shù)名: strstr
函數(shù)原型:
1
extern char *strstr(char *str1, const char *str2);
語法:
1
* strstr(str1,str2)
str1: 被查找目標(biāo) string expression to search.
str2: 要查找對象 The string expression to find.
返回值:若str2是str1的子串,則返回str2在str1的首次出現(xiàn)的地址;如果str2不是str1的子串,則返回NULL。
例子:
1
2
3
char str[]="1234xyz";
char *str1=strstr(str,"34");
cout << str1 << endl;
顯示的是: 34xyz
函數(shù)實現(xiàn)
1.Copyright 1990 Software Development Systems, Inc.
1
2
3
4
5
6
7
8
9
10
11
12
char *strstr(const char *s1,const char *s2)
{
int len2;
if(!(len2=strlen(s2)))//此種情況下s2不能指向空,否則strlen無法測出長度,這條語句錯誤
return(char*)s1;
for(;*s1;++s1)
{
if(*s1==*s2 && strncmp(s1,s2,len2)==0)
return(char*)s1;
}
return NULL;
}
2.Copyright 1986 - 1999 IAR Systems. All rights reserved
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char *strstr(constchar*s1,constchar*s2)
{
int n;
if(*s2)
{
while(*s1)
{
for(n=0;*(s1+n)==*(s2+n);n++)
{
if(!*(s2+n+1))
return(char*)s1;
}
s1++;
}
return NULL;
}
else
return (char*)s1;
}
3. GCC-4.8.0
1
2
3
4
5
6
7
8
9
10
11
char *strstr(const char*s1,const char*s2)
{
const char*p=s1;
const size_tlen=strlen(s2);
for(;(p=strchr(p,*s2))!=0;p++)
{
if(strncmp(p,s2,len)==0)
return (char*)p;
}
return(0);
}
應(yīng)用舉例
// strstr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include
#include
main()
{
char *s="GoldenGlobalView";
char *l="lob";
char *p;
clrscr();
p=strstr(s,l);
if(p)
printf("%s",p);
else
printf("NotFound!");
get);
return0;
}
//功能:從字串” string1 onexxx string2 oneyyy”中尋找”yyy”
(假設(shè)xxx和yyy都是一個未知的字串)
1
2
3
4
5
6
7
char *s=”string1onexxxstring2oneyyy”;
char *p;
p=strstr(s,”yyy”);
if(p!=NULL)
printf(“%s”,p);
else
printf("notfound ");
說明:如果直接寫語句p=strstr(s,”one”),找到的是onexxxstring2oneyyy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
char *mystrstr(char*s1,char*s2)
{
if(*s1==0)
{
if(*s2)
return (char*)NULL;
return (char*)s1;
}
while(*s1)
{
int i=0;
while(1)
{
if(s2[i]==0)
return s1;
if(s2[i]!=s1[i])
break;
i++;
}
s1++;
}
return (char*)NULL;
}
C語言的一些誤用和知識總結(jié)
具體如下:
1.關(guān)于自增自減(即++i,i++)
要想給一個數(shù)加一或減一我們可以:
i += 1;
j -= 1;
而C語言還允許用++和--運算符,其實這里有誤導(dǎo),因為++和--可以作為前綴和后綴,這樣的話他們就有可能改變操作數(shù)的值,下面讓我們來看看:
i = 1;
printf("i is %d ",++i); /* prints i is 2 */
printf("i is %d ",i); /* prints i is 2 */
計算表達(dá)式i++的結(jié)果是i,但是會引發(fā)i隨后進(jìn)行自增:
i = 1;
printf("i is %d ",i++); /* prints i is 1/ */
printf("i is %d ",i); /* prints i is 2 */
第一個printf 顯示了i自增前的原始值,第二個printf顯示了i變化后的新值;當(dāng)然 -- 類似我就不舉例了~
但在同一個表達(dá)式中多次使用++和--往往很難理解我們看看下面的例子:
i = 1;
j = 2;
k = ++i + j++;
i,j,k最終值分別是2,3,4而++i是2 j++是2;
總結(jié):不管是++i還是i++執(zhí)行這條語句后i的值都加一了只是(++i)的值加一了而(i++)沒變,
2.typedef與#define
2.1.typedef
C語言除了直接使用標(biāo)準(zhǔn)的類型名(如 int char float double)和自己聲明的結(jié)構(gòu)體、共用體、指針、枚舉類型外,還可以用typedef聲明新的類型名來代替現(xiàn)有的類型名。
typedef unsigned char u8;
typedef unsigned int u16;
u8 count;
u16 time;
typedef struct
{
u8 month;
u8 day;
u16 year;
}DATE;
DATE brithday;
總結(jié)一下,聲明新的類型名的方法:
1.先按定義變量的方法寫出定義體(如 unsigned int i)
2.在變量名換成新的變量名(如將 i換成u16)
3.在最前面加上typedef (typedef unsigned int u16)
4.然后用新類型名去定義變量
2.2#define
2.1.1不帶參數(shù)的宏定義
define 標(biāo)識符 字符串
define PI 3.1415926
注意:
1.它的作用是在本程序中用指定的標(biāo)識符PI來代替3.1415926
2.宏定義是用宏來代替字符串也就是做簡單的置換,不做正確性檢查如果寫成
define PI 3.l4l6926
即把1寫成了字母l但是預(yù)處理照常代入不做任何語法檢查!!
2.1.2帶參數(shù)的宏定義
define 宏名(參數(shù)) 字符串
define S(a,b) a*b
area = S(a,b);
define MAX(x,y) (x)>(y) ? (x):(y)
3.typedef和#define的區(qū)別
一般來說typedef 因為它能正確處理指針類型
typedef char *String1;
define String2 char *
String1 s1,s2;
String2 s3,s4;
s1,s2,s3 被定義為了char* 但s4卻被定義為了char型
3. static 變量
static變量大致分為三種用法
1. 用于局部變量中,成為靜態(tài)局部變量. 靜態(tài)局部變量有兩個用法,記憶功能和全局生存期.
2. 用于全局變量,主要作用是限制此全局變量被其他的文件調(diào)用.
3. 用于類中的成員.表示這個成員是屬于這個類但是不屬于類中任意特定對象
靜態(tài)局部變量
靜態(tài)局部變量屬于靜態(tài)存儲方式,它具有以下特點:
(1)靜態(tài)局部變量在函數(shù)內(nèi)定義 它的生存期為整個源程序,但是其作用域仍與自動變量相同,只能在定義該變量的函數(shù)內(nèi)使用該變量。退出該函數(shù)后, 盡管該變量還繼續(xù)存在,但不能使用它。
(2)允許對構(gòu)造類靜態(tài)局部量賦初值 例如數(shù)組,若未賦以初值,則由系統(tǒng)自動賦以0值。
(3) 對基本類型的靜態(tài)局部變量若在說明時未賦以初值,則系統(tǒng)自動賦予0值。而對自動變量不賦初值,則其值是不定的。 根據(jù)靜態(tài)局部變量的特點, 可以看出它是一種生存期為整個源程序的量。雖然離開定義它的函數(shù)后不能使用,但如再次調(diào)用定義它的函數(shù)時,它又可繼續(xù)使用, 而且保存了前次被調(diào)用后留下的值。 因此,當(dāng)多次調(diào)用一個函數(shù)且要求在調(diào)用之間保留某些變量的值時,可考慮采用靜態(tài)局部變量。雖然用全局變量也可以達(dá)到上述目的,但全局變量有時會造成意外的副作用,因此仍以采用局部靜態(tài)變量為宜。
舉例如下:
void fun()
{
static int a = 1;
a++;
}
在第一次進(jìn)入這個函數(shù)的時候,變量a被初始化為1!并接著自增1,以后每次進(jìn)入該函數(shù),a就不會被再次初始化了,僅進(jìn)行自增1的操作;在static發(fā)明前,要達(dá)到同樣的功能,則只能使用全局變量:
int a = 1;
void fun()
{
a++;
}
靜態(tài)全局變量
全局變量(外部變量)的之前再加上static 就構(gòu)成了靜態(tài)的全局變量。全局變量本身就是靜態(tài)存儲方式, 靜態(tài)全局變量當(dāng)然也是靜態(tài)存儲方式。 這兩者在存儲方式上并無不同。這兩者的區(qū)別雖在于,非靜態(tài)全局變量的作用域是整個源程序, 當(dāng)一個源程序由多個源文件組成時,非靜態(tài)的全局變量在各個源文件中都是有效的。 而靜態(tài)全局變量則限制了其作用域, 即只在定義該變量的源文件內(nèi)有效, 在同一源程序的其它源文件中不能使用它。由于靜態(tài)全局變量的作用域局限于一個源文件內(nèi),只能為該源文件內(nèi)的函數(shù)公用, 因此可以避免在其它源文件中引起錯誤。從以上分析可以看出, 把局部變量改變?yōu)殪o態(tài)變量后是改變了它的存儲方式即改變了它的生存期。把全局變量改變?yōu)殪o態(tài)變量后是改變了它的作用域, 限制了它的使用范圍。因此static 這個說明符在不同的地方所起的作用是不同的。
static的類成員變量
static關(guān)鍵字有兩種意思,你看上下文來判斷
1.表示變量是靜態(tài)存儲變量,表示變量存放在靜態(tài)存儲區(qū).
2.表示該變量是內(nèi)部連接(這種情況是指該變量不在任何{}之內(nèi),就象全局變量那樣,這時候加上static),也就是說在其它的.cpp文件中,該變量是不可見的(你不能用)。
static 函數(shù) —— 內(nèi)部函數(shù)和外部函數(shù)
當(dāng)一個源程序由多個源文件組成時,C語言根據(jù)函數(shù)能否被其它源文件中的函數(shù)調(diào)用,將函數(shù)分為內(nèi)部函數(shù)和外部函數(shù)。
1 內(nèi)部函數(shù)(又稱靜態(tài)函數(shù))
如果在一個源文件中定義的函數(shù),只能被本文件中的函數(shù)調(diào)用,而不能被同一程序其它文件中的函數(shù)調(diào)用,這種函數(shù)稱為內(nèi)部函數(shù)。
定義一個內(nèi)部函數(shù),只需在函數(shù)類型前再加一個“static”關(guān)鍵字即可,如下所示:
static 函數(shù)類型 函數(shù)名(函數(shù)參數(shù)表)
{……}
關(guān)鍵字“static”,譯成中文就是“靜態(tài)的”,所以內(nèi)部函數(shù)又稱靜態(tài)函數(shù)。但此處“static”的含義不是指存儲方式,而是指對函數(shù)的作用域僅局限于本文件。
使用內(nèi)部函數(shù)的好處是:不同的人編寫不同的函數(shù)時,不用擔(dān)心自己定義的函數(shù),是否會與其它文件中的函數(shù)同名,因為同名也沒有關(guān)系。
2 外部函數(shù)
外部函數(shù)的定義:在定義函數(shù)時,如果沒有加關(guān)鍵字“static”,或冠以關(guān)鍵字“extern”,表示此函數(shù)是外部函數(shù):
[extern] 函數(shù)類型 函數(shù)名(函數(shù)參數(shù)表)
{……}
調(diào)用外部函數(shù)時,需要對其進(jìn)行說明:
[extern] 函數(shù)類型 函數(shù)名(參數(shù)類型表)[,函數(shù)名2(參數(shù)類型表2)……];
詞條內(nèi)容僅供參考,如果您需要解決具體問題
(尤其在法律、醫(yī)學(xué)等領(lǐng)域),建議您咨詢相關(guān)領(lǐng)域?qū)I(yè)人士。