字符串的指针和指向字符串的指针变量
§8.4 字符串的指針和指向字符串的指針變量
8.4.1 字符串的表現(xiàn)形式
在C程序中,可以用兩種方法實(shí)現(xiàn)一個字符串。
1. 用字符數(shù)組實(shí)現(xiàn)。
[例8.11]
void main(void)
{static char string [ ]="I Love China!";
printf("%s\n",string);
}
運(yùn)行時輸出: I Love China!
和前面介紹的數(shù)組屬性一樣,string是數(shù)組名,它代表字符數(shù)組的首地址,(見圖8.17)。string[4]代表數(shù)組中序號為4的元素(v),實(shí)際上string[4]就是*(string+4),string+4是指向字符“v”指針。
2. 用字符指針實(shí)現(xiàn)。
可以不定義字符數(shù)組,而定義一個字符指針。用字符指針指向字符串中的字符。
[例8.12]
void main(void)
{char *string="I Love China!";
printf("%s\n",string);
}
在這里沒有定義字符數(shù)組,但C語言對字符串常量是按字符數(shù)組處理的,實(shí)際上在內(nèi)存開辟了一個字符數(shù)組用來存放字符串?dāng)?shù)組。在程序中定義了一個字符指針變量string。并把字符串首地址(即存放字符串的字符數(shù)組的首地址)賦給它(見圖8.18)。有人認(rèn)為string是一個字符串變量,以為定義時把"I Love China!"賦給該字符串變量,這是不確切的。定義string的部分:
char *string="I Love China!";
等價于下面兩行:
char *string;
string="I Love China!";
可以看到:string被定義為一個指針變量,它指向字符型數(shù)據(jù),請注意只能指向一個字符變量或其它字符類型數(shù)據(jù),不能同時指向多個字符數(shù)據(jù),更不是把"I Love China!"這些字符存放到string中。只是把"I Love China!"的首地址賦給指針變量string(不是把字符串賦給*string)。因此不要認(rèn)為上述定義行等價于:
char *string;
*string="I Love China!";
在輸出時,用
printf("%s\n",string);
%s表示輸出一個字符串,給出字符指針變量名string,則系統(tǒng)先輸出它所指向的一個字符數(shù)據(jù),然后自動使string加1,使之指向下一個字符,然后再輸出一個字符,……,如此直到遇到字符串結(jié)束標(biāo)志‘\0’為止。注意,在內(nèi)存中,字符串的最后被自動加了一個‘\0’(如圖8.18所示),因此在輸出時能確定字符串的終止位置。
通過字符數(shù)組名或字符指針變量可以輸出一個字符串。而對一個數(shù)值型數(shù)組,是不能企圖用數(shù)組名輸出它的全部元素的。如:
int i[10]
:
printf("%d\n",i);
是不行的,只能逐個元素輸出。顯然,可以把字符串看作為一個整體來處理,可以對一個字符串進(jìn)行整體的輸入輸出。
對字符串中字符的存取,可以用下標(biāo)方法,也可以用指針方法。
[例8.13]將字符串a復(fù)制得字符串b。
void main(void)
{char a[ ]= "I am a boy. ",b[20];
int i;
for(i=0;*(a+i)!=‘\0’;i++)
*(b+i)=*(a+i);
*(b+i)=‘\0’;
printf("string a is:%s\n",a);
printf("string b is: ");
for(i=0;b[i]!=‘\0’;i++)
printf("%c",b[i]);
printf("\n");
}
程序運(yùn)行結(jié)果為:
string a is:I am a boy.
string b is:I am a boy.
程序中a和b都定義為字符數(shù)組,可以用地址方法表示數(shù)組元素。在for語句中,先檢查a[i]是否為’\0’(今a[i]是以*(a+i)形式表示的)。如果不等于’\0’,表示字符串尚未處理完,就將a[i]的值賦給b[i],即復(fù)制一個字符。在for循環(huán)中將a串全部復(fù)制給了b串。最后還應(yīng)將’\0’復(fù)制過去,故有:*(b+i)=‘\0’;
此時的i的值是字符串有效字符的個數(shù)n加1。第二個for循環(huán)中用下標(biāo)法表示一個數(shù)組元素(即一個字符)。也可以設(shè)指針變量,用它的值的改變來指向字符串中的不同的字符。
[例8.14] 用指針變量來處理例8.13問題。
void main(void)
{char a[ ]= "I am a boy. ",b[20],*p1,*p2;
int i;
p1=a;p2=b;
for(;*p1!=‘\0’;p1++,p2++)
*p2=*p1;
*p2=‘\0’;
printf("string a is:%s\n",a);
printf("string b is: ");
for(i=0;b[i]!=‘\0’;i++)
printf("%c",b[i]);
printf("\n");
}
p1,p2是指針變量,它指向字符型數(shù)據(jù),先使p1和p2的值分別為字符串a和b的首地址。*p1最初的值為‘i’,賦值語句“*p2=*p1;”的作用是將字符’I’(a串中第一個字符)賦給p2所指向的元素,直到 *p1的值為’\0’止。注意p1和p2的值是不斷在改變的,程序必須保證使p1和p2同步移動。
8.4.2 字符串指針作函數(shù)參數(shù)
將一個字符串從一個函數(shù)傳遞到另一個函數(shù),可以用地址傳遞的辦法,即用字符數(shù)組名作參數(shù)或用指向字符串的指針作參數(shù)。在被調(diào)用的函數(shù)中可以改變字符串的內(nèi)容,在主調(diào)函數(shù)中可以得到改變了的字符串。
[例8.15] 用函數(shù)調(diào)用實(shí)現(xiàn)字符串的復(fù)制。
(1)用字符數(shù)組作參數(shù)
void copy_string (char from[ ],char to[ ])
{int i=0;
while (from[i]!=‘\0’)
{to[i]=from[i];i++;}
to[i]=‘\0’;
}
void main(void)
{char a[ ]= "I am a teacher. ";
char b[ ]= "You are a student. ";
printf("string_a=%s\n string_b=%s\n",a,b);
copy_string(a,b);
printf("\nstring_a=%s\n string_b=%s\n",a,b);
}
程序運(yùn)行結(jié)果如下:
string_a=I am a teacher.
string_b=You are a student.
string_a=I am a teacher.
string_b=I am a teacher.
a和b是字符數(shù)組。初值如圖8.19(a)所示。copy_string函數(shù)的作用是將from[i]賦給to[i],直到from[i]的值為’\0’為止。在調(diào)用copy_string函數(shù)時,將a和b的首地址分別傳遞給形參數(shù)組form和to。因此from[i]和a[i]是同一個單元,to[i]和b[i]是同一個單元。程序執(zhí)行完以后,b數(shù)組的內(nèi)容如圖8.19(b)所示??梢钥闯?#xff0c;由于b數(shù)組原來的長度大于a數(shù)組,因此在a數(shù)組復(fù)制到b數(shù)組后,未能全部覆蓋b數(shù)組原有內(nèi)容。b數(shù)組最后三個元素仍保留原狀。在輸出b時由于按%s(字符串)輸出,遇’\0’即告結(jié)束,因此第一個’\0’后的字符不輸出。如果不采取%s格式輸出而用%c逐個字符輸出是可以輸出后面這些字符的。
在main函數(shù)中也可以不定義字符數(shù)組,而用字符型指針變量。main函數(shù)可改寫如下:
void main(void)
{char *a=“I am a teacher.”;
char *b= “You are a student.”;
printf(“string_a=%s\n
string_b=%s\n”,a,b);
copy_string(a,b);
printf(“\nstring_a=%s\n
string_b=%s\n”,a,b);
}
與上面程序運(yùn)行結(jié)果相同。
(2)形參用字符指針變量
程序如下:
void copy_string(char *from,char *to)
{
for(;*from!=‘\0’;from++,to++)
*to=*from;
*to=‘\0’;
}
void main(void)
{char *a="I am a teacher. ";
char *b= "You are a student. ";
printf("string_a=%s\n
string_b=%s\n",a,b);
copy_string(a,b);
printf("\nstring_a=%s\n string_b=%s\n",a,b);
}
形參form和to是字符指針變量。它們相當(dāng)于例8.19中的p1和p2。算法也與例8.19完全相同。在調(diào)用copy_string時,將數(shù)組a的首地址傳給from,把數(shù)組b的首地址傳給to。在函數(shù)copy_string中的for循環(huán)中,每次將*from賦給*to,第1次就是將a數(shù)組中第1個字符賦給b數(shù)組的第1個字符。在執(zhí)行from++和to++以后,from和to就分別指向a[1]和b[1]。再執(zhí)行*to=*from,就將a[1]賦給b[1],……。最后將’\0’賦給*to,注意此時to指向哪個單元。
(3)對copy_string函數(shù)還可作簡化
1. 將copy_string函數(shù)改寫為:
void copy_string (char *from,char *to)
{
while ((*to=*from)!=‘\0’)
{to++;from++;}
}
請與上面一個程序?qū)Ρ?。在本程序中將?/font>*to=*from;”的操作放在while語句的表達(dá)式中,把賦值運(yùn)算和判斷是否為’\0’的運(yùn)算放在表達(dá)式中,先賦值后判斷。在循環(huán)體中to和from增值,指向下一個元素,……,直到*from的值為’\0’為止。
2. copy_string函數(shù)的函數(shù)體還可改為:
{
while((*to++=*from++)!=‘\0’);
}
把上面程序的to++和from++運(yùn)算與*to=*from合并,它的執(zhí)行過程是:先將*from賦給*to,然后使to和from增值。顯然這又簡化了。
3. 函數(shù)體還可寫成:
{
while(*from!=‘\0’)
*to++=*from++;
*to=‘\0’;
}
當(dāng)*from不為’\0’時,使*from賦給*to,然后使to和from增值。
字符可以用其ASCII代碼來代替。例如:”ch=‘a(chǎn)’”可以用”ch=97”代替,”while(ch!=‘a(chǎn)’)”可以用”while(ch!=97)”代替。因此,”while(*from!=‘\0’)”可以用”while(*from!=0)代替(’\0’的ASCII代碼為0)。而關(guān)系表達(dá)式”*from!=0”又可簡化為”*from”,這是因?yàn)槿?/font>*form的值不等于0,則表達(dá)式”*from”為真,同時”*from!=0”也為真。因此”while(*from!=0)”和”while(*from)”是等價的。所以函數(shù)體可簡化為:
{while(*from)
*to++=*from++;
*to=‘\0’;}
4. 上面的while語句還可以進(jìn)一步簡化為下面的while語句:
while(*to++=*from++)
它與下面語句等價:
while((*to++=*from++)!=‘\0’);
將*from賦給*to,如果賦值后的*to值等于’\0’,則循環(huán)終止(’\0’已賦給*to)。
5. 函數(shù)體中while語句也可以改用for語句:
for(;(*to++=*from++)!=0;);
或 for(;*to++=*from;);
6. 也可用指針變量,函數(shù)copy_string可寫為:
void copy_string( char from[ ],char to[ ])
{char *p1,*p2;
p1=from;p2=to;
while((*p2++=*p1++)!=‘\0’);
}
以上各種用法,變化多端,使用十分靈活,初看起來不太習(xí)慣,含義不直觀。初學(xué)者會有些困難,也容易出錯。但對C熟練之后,以上形式的使用是比較多的,讀者應(yīng)逐漸熟悉它,掌握它。
歸納起來,作為函數(shù)參數(shù),有以下幾種情況:
實(shí) 參 形 參
1. 數(shù) 組 名 數(shù) 組 名
2. 數(shù) 組 名 字符指針變量
3. 字符指針變量 字符指針變量
4. 字符指針變量 數(shù) 組 名
8.4.3 字符指針變量與字符數(shù)組
雖然用字符數(shù)組和字符指針變量都能實(shí)現(xiàn)字符串的存儲和運(yùn)算,但它們二者之間是有區(qū)別的,不應(yīng)混為一談,主要有以下幾點(diǎn):
1. 字符數(shù)組由若干個元素組成,每個元素中放一個字符,而字符指針變量中存放的是地址(字符串的首地址),決不是將字符串放到字符指針變量中。
2. 賦初值的方式。對數(shù)組賦初值要用static存儲類別,如
static str[ ]={ "I love China! ");
而對字符指針變量不必加static存儲類型,如
char *a="I love China! ";
這是因?yàn)椴]有對數(shù)組初始化,只是對指針變量初始化。
3. 賦值方式。對字符數(shù)組只能對各個元素賦值,不能用以下辦法對字符數(shù)組賦值。
char str[14];
str="I love China! ";
而對字符指針變量,可以采用下面方法賦值:
char *a;
a="I love China! ";
但注意賦給a的不是字符,而是字符串的首地址。
4. 賦初值時,對以下的變量定義和賦初值:
char *a="I love China! ";
等價于:
char *a;
a="I love China! ";
而對數(shù)組初始化時:
static char str[14]={ "I love China! "};
不是等價于
char str[14];
str[ ]= "I love China! ";
即數(shù)組可以在變量定義時整體賦初值,但不能在賦值語句中整體賦值。
5. 在定義一個數(shù)組時,在編譯時即已分配內(nèi)存單元,有確定的地址。而定義一個字符指針變量時,給指針變量分配內(nèi)存單元,在其中可以放一個地址值,也就是說,該指針變量可以指向一個字符型數(shù)據(jù),但如果未對它賦以一個地址位,則它并未具體指向哪一個字符數(shù)據(jù)。如:
char str[10];
scanf("%s",str);
是可以的,而常有人用下面的方法:
char *a;
scanf("%s",a);
目的是輸入一個字符串,雖然一般也能運(yùn)行,但這種方法是危險的,不宜提倡。因?yàn)榫幾g時雖然分配給指針變量a一個單元,a的地址(即&a)是已指定了,但a的值并未指定,在a單元中是一個不可預(yù)料的值。因此在scanf函數(shù)中要求將一個字符串輸入到a的值(地址)開始的存儲區(qū)(這是好的情況),也有可能指向已存放指令或數(shù)據(jù)的內(nèi)存段,這就會破壞了程序,甚至?xí)斐蓢?yán)重的后果。在程序規(guī)模小時,由于空白地帶多,往往可以正常運(yùn)行,而程序規(guī)模大時,出現(xiàn)上述“沖突”的可能性就大多了。應(yīng)當(dāng)這樣:
char *a,str[10];
a=str;
scanf("%s",a);
先使a有確定值,也就是使a指向一個數(shù)組的開頭,然后輸入字符串到該地址開始的若干單元中。
6. 指針變量的值是可以改變的,如:
[例8.16]
void main(void)
{char *a="I love China! ";
a=a+7;
printf("%s",a);
}
運(yùn)行結(jié)果如下:
China!
指針變量a的值可以變化,輸出字符串從a當(dāng)時所指向的單元開始輸出各個字符,直到遇’\0’為止。而數(shù)組名雖然代表地址,但它的值是不能改變的。下面是錯的:
char str[ ]={ "I love China! "};
str=str+7;
printf("%s",str);
需要說明:若定義了一個指針變量,使它指向一個字符串后,可以用下標(biāo)形式引用指針變量所指的字符串中的字符。如:
[例8.17]
void main(void)
{char *a="I LOVE CHINA. ";
int i;
printf("The sixth charcter is %c\n",a[5]);
for(i=0;a[i]!=‘\0’;i++)
printf("%c",a[i]);
}
運(yùn)行結(jié)果如下:
The sixth charcter is E
I LOVE CHINA.
程序中雖然并未定義數(shù)組a,但字符串在內(nèi)存中是以字符數(shù)組形式存放的。a[5]按*(a+5)執(zhí)行,即從a當(dāng)前所指向的元素下移5個元素的位置,取出其單元中的值。
7. 用指針變量指向一個格式字符串,可以用它代替printf函數(shù)中的格式字符串。如:
char *format;
format="a=%d,b=%f\n";
printf(format,a,b);
它相當(dāng)于
printf("a=%d,b=%f\n",a,b);
因此只要改變指針變量format所指向的字符串,就可以改變輸入輸出的格式。這種printf函數(shù)稱為可變格式輸出函數(shù)。
也可以用字符數(shù)組。如:
char format[ ]= "a=%d,b=%f\n";
printf(format,a,b);
但由于不能采取賦值語句對數(shù)組整體賦值的形式,如:
char format[ ];
format="a=%d,b=%f\n";
因此用指針變量指向字符串的方式更為方便。
y3= 1.29
轉(zhuǎn)載于:https://www.cnblogs.com/inspurhaitian/archive/2008/09/05/1285027.html
總結(jié)
以上是生活随笔為你收集整理的字符串的指针和指向字符串的指针变量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: as3corelib系列教程之一:Arr
- 下一篇: 简单文件的上传与保存