在C语言入门教材里看到这一段代码,没看懂是什么意思。
char buffer[10];
char *pbuffer = buffer;
while( (*pbuffer++ = getchar() )!= '
');
*pbuffer = ' ';
尤其是第三段while( (*pbuffer++ = getchar() )!= '
'); 这里的getchar取的是什么数据,是我输入的数据吗?*pbuffer是一个指针数组吗,是不是存了输入的所有信息?
*buffer不是指针数组,是一个字符型的指针,让指针pbuffer指向了数组buffer的首地址,那么*pbuffer就跟buffer[0]是等价的,而pbuffer++的意思就是让pbuffer指向当前所指的下一个单元。也就是说执行完pbuffer++以后,*pbuffer就和buffer[1]等价。
while( (*pbuffer++ = getchar() )!= ' ');的作用是读取输入的字符到buffer中,遇到换行符停止读取。
getchar的意思是读取一个字符变量并返回,
那这段代码执行完之后,*pbuffer这个指针存的是什么内容?
未知的。
执行完*pbuffer = getchar()后 pbuffer又自加了一次,此时pbuffer是指向的地址是' '的下一个元素的地址,而这个值你的代码里边并没有给出结果,所以是未知的。
指针的学习(四)——指针处理字符串
1、指针处理字符串
我们可以用char类型的数组变量存储字符串,也可以使用char类型的指针变量引用字符串。这个方法在处理字符串时非常灵活。如下所示:
char *pString = NULL;
注意,指针只是一个存储另一个内存位置的地址变量。前面只创建了指针,没有指定一个存储字符串的地方。要存储字符串,需要分配一些内存。可以声明一块内存,来存储字符串数据,然后使用指针追踪这块存储字符串的内存。
1、使用指针更多的控制字符串输入
在读取文本时,常需要比scanf()函数更多的控制。在<stdio.h>中声明的getchar()函数提供了非常基本的操作,一次只读取一个字符,但是它可控制何时停止读入字符。这样就可以确保不会超过存储输入而分配的内存。
getchar()函数从键盘读入一个字符,并以int类型返回。可以把一个结尾‘ '的字符串读入所定义的数组中。如下
char buffer[100];
char *pbuffer = buffer;
while((*pbuffer++ = getchar() != ' ');
*pbuffer = ' ';
所有的输入都在while循环的条件中完成。getchar()函数读取一个字符,并它存储在pbuffer的当前地址中。然后,递增pbuffer中的地址,以指向下一个字符。在循环结束后,将' '字符添加到下一个可用的位置上。
2、使用指针数组
处理多个字符串时,可以在堆上使用指针数组存储对字符串的引用。下面用一个例子来说明
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#include <stdio.h>const size_t BUFFER_LEN = 512;int main(void){ char buffer[BUFFER_LEN]; char *pS[3] = { NULL }; char *pbuffer = buffer; size_t index = 0; int i; printf("\nEnter 3 messages that total less than %u characters.", BUFFER_LEN - 2); for(i = 0; i < 3; i++) { printf("\nEnter %s message\n", i > 0 ? "another" : "a"); pS[i] = &buffer[index]; for(; index < BUFFER_LEN; index++) if((*(pbuffer + index) = getchar()) == '\n') { *(pbuffer + index++) = '\0'; break; } if((index == BUFFER_LEN) && ((*(pbuffer + index - 1) != '\0') || (i < 2))) { printf("\nYou ran out of space in the buffer."); return 1; } } printf("\nThe string you entered are:\n\n"); for(i = 0; i < 3; i++) printf("%s\n", pS[i]); printf("The buffer has %d characters unused.\n", BUFFER_LEN - index); return 0;} |
结束输出如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Enter 3 messages that total less than 510 characters.Enter a messageHello CEnter another messageToday is a great day for learnginEnter another messageso start lenThe string you entered are:Hello CToday is a great day for learnginso start lenThe buffer has 457 characters unused. |
代码说明:
首先定义全局变量BUFFER_LEN指定buffer数组的大小
const size_t BUFFER_LEN = 512;
这个变量必须声明为const,才能用来指定数组大小;数组的大小只能用常量式来指定。
接着就是主函数定义
|
1
2
3
4
5
|
char buffer[BUFFER_LEN]; char *pS[3] = { NULL }; char *pbuffer = buffer; size_t index = 0; int i; |
|
1
|
buffer数组的类型是char,有BUFFER_LEN个元素。pS数组有3个指针存储buffer数组中字符串的地址。pbuffer指针用buffer数组中的第一个字节的地址初始化在输入字符时,要用pbuffer遍历buffer数组。index变量记录buffer数组中当前未使用的元素位置。 |
|
1
|
第一个for循环读取3个字符串。循环中的第一条语句如下: |
|
1
|
printf("
Enter %s message
", i >0 ? "another" : "a"); |
|
1
|
这里通过一种简洁的方式使用条件运算符,在for循环的第一次迭代后修改提示。 |
|
1
|
该语句在第一次迭代时输出a,在后续的迭代中输出;another。 |
|
1
|
下一条语句将当前保存在pbuffer中的地址存储到指针数组中: |
|
1
|
pS[i] = &buffer[index]; |
|
1
|
上述赋值语句把指针pbuffer中的地址保存到指针数组pS的一个元素中 |
|
1
|
读取字符串并添加字符串终止符的语句如下: |
|
1
|
for(; index < BUFFER_LEN; index++) |
|
1
|
if((*(pbuffer + index) = getchar()) == '
'; |
|
1
|
{ |
|
1
|
*(pbuffer + index++) = ' '; |
|
1
|
break; |
|
1
|
} |
|
1
|
这个for循环就是用于读取到buffer数组未尾的循环。如果读入一个'
'就用' '替代它,并结束循环结束后,检查bffer数组是否还没有达到字符串的未尾就已满: |
|
1
|
if((index == BUFFER_LEN) && ((*(pbuffer + index - 1) != ' ') || (i < 2))) |
|
1
|
{ |
|
1
|
printf("
You ran out of space in the buffer.") |
|
1
|
return 1; |
|
1
|
} |
|
1
|
使用getchar()读取字符串,可以对输入过程进行很多控制。这种方法并不ur公限于读取字符串,还可以用于读取逐个处理字符串的所有输入过程。可以从输入中删除空格,或者查找特定的字符,例如用于分隔各个输入值的逗号。 |
|
1
|
printf("
The string you entered are:
"); |
|
1
|
for(i = 0; i < 3; i++) |
|
1
|
printf("%s
", pS[i]); |
|
1
|
在循环中,输出pS指向的每一个元素中的字符串。 |
|
1
|
在最后一个printf()中,输出字符串中剩下的字符个数: |
|
1
|
printf("The buffer has %d characters unused.
", BUFFER_LEN - index); |
|
1
|
从buffer数组的元素个数中减去index,得到未使用的元素个数 |
|
1
|
下面来修改一下这个程序让它实现输入任意个字符串: |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
<pre class="cpp;">#include <stdio.h>#include <stdlib.h>#include <string.h>#define NUM_P 100const size_t BUFFER_LEN = 128;int main(void){ char buffer[BUFFER_LEN]; char *pS[NUM_P] = { NULL }; char *pbuffer = buffer; int i = 0; printf("\nYou can enter up to %u message each up to %u characters.", NUM_P, BUFFER_LEN - 1); for(i = 0; i < NUM_P; i++) { pbuffer = buffer; printf("\nEnter %s message, or press Enter to end\n", i > 0 ? "another" : "a"); while((pbuffer - buffer < BUFFER_LEN - 1) && ((*pbuffer++ = getchar()) != '\n')); if((pbuffer - buffer) < 2) break; if((pbuffer - buffer) == BUFFER_LEN && *(pbuffer - 1) != '\n') { printf("String too long - maxmum %d Characters allowed.", BUFFER_LEN); i--; } *(pbuffer - 1) = '\0'; pS[i] = (char*)malloc(pbuffer - buffer); if(pS[i] == NULL) { printf("\nOut of memory - ending program."); return 1; } strcpy(pS[i],buffer); } printf("\nIn reverse order, the string you entered are:\n"); while(--i >= 0) { printf("\n%s", pS[i]); free(pS[i]); pS[i] = NULL; } return 0;}</pre><pre class="cpp;">输出的结果如下:</pre><pre class="cpp;"><pre class="cpp;">You can enter up to 100 message each up to 127 characters.Enter a message, or press Enter to end12344555;34344Enter another message, or press Enter to endzidfjdjfadifdaEnter another message, or press Enter to endfdfjdjfdsaEnter another message, or press Enter to endIn reverse order, the string you entered are:fdfjdjfdsazidfjdjfadifda12344555;34344</pre></pre> |
|
1
|
这个代码与上一个相比,这个程序稍有扩展,但涵盖了相当多的内容。现在可以处理任意数量的字符串,能处理的最大字符串是数组pS中的指针数。这个数组的大小在程序起始定义,以便于修改。 |
|
1
|
#define NUM_P 100; (这个是gcc编译器下的,也可以是const size_t NUM_P = 100;) |
|
1
|
只要修改这个数字就可以改变这个程序能处理的最大的字符串数。在main()函数中声明如下: |
|
1
2
3
4
5
|
<pre class="as3;">char buffer[BUFFER_LEN]; char *pS[NUM_P] = { NULL }; char *pbuffer = buffer; int i = 0;</pre><pre class="as3;">buffer数组只是一个输入缓冲区,含有每个读入的字符串。因此#define指令将BUFFER_LEN定义为能接受的字符串最大长度。然后,声明指针数组的长度NUM_P和指针puffer,以用于buffer数组。最后是两个循环控制变量。</pre> |
|
1
|
下面显示一条信息,说明输入的限制: |
|
1
2
3
4
5
6
7
8
|
<pre class="cpp;" style="text-indent:24px;">printf("\nYou can enter up to %u message each up to %u characters.", NUM_P, BUFFER_LEN - 1);</pre><pre class="cpp;" style="text-indent:24px;">输入信息的最大长度允许加上终止字符。</pre><pre class="cpp;" style="text-indent:24px;">第一个for循环读入字符串并存储它们。这个循环控制如下:</pre><pre class="cpp;" style="text-indent:24px;">for(i = 0; i < NUM_P; i++)</pre><pre class="cpp;" style="text-indent:24px;">这能确保输入的字符串不超过前面声明的指针数量。一旦输入的字符串数到达最大字符串数,循环就会结束,进入程序的输出部分。</pre><pre class="cpp;" style="text-indent:24px;">在循环中,字符串输入使用类似getchar()的机制,但是多了一个额外的条件:</pre><pre class="cpp;" style="text-indent:24px;">while((pbuffer - buffer < BUFFER_LEN - 1) && ((*pbuffer++ = getchar()) != '
'));</pre><pre class="cpp;" style="text-indent:24px;">整个过程发生在while循环的条件式中。由getchar()得到的字符存储在pbuffer指向的地址中,pbuffer最初保存的是buffer的地址。然后递增pbuffer指针,指向下一个可用的空间,这个赋值语句所存储的字符与'
'比较,若该字符是'
',就结束循环。如果pbuffer - buffer < BUFFER_LEN - 1 是false,循环也会结束。即如果下一个要存储的字符占据了buffer数组的最后一个位置,循环也会结束。</pre> |
|
1
|
输入过程结束后,用下面的语句进行检查: |
|
1
|
if((pbuffer = buffer) < 2) |
|
1
|
break; |
|
1
|
这个语句检测空行,因为如果只按下回车键,就只输入一个字符'
'。此时,break语句立即结束循环,开始输出过程。 |
|
1
|
下一个if语句检查是否试图输入超过buffer容量的字符串: |
|
1
|
if((pbuffer - buffer) == BUFFER_LEN && *(pbuffer - 1) != '
') |
|
1
|
{ |
|
1
|
printf("String too long - maxmum %d character allowed.", BUFFER_LEN); |
|
1
|
i--; |
|
1
|
} |
|
1
|
因为使用了buffer数组的最后一个位置时,会结束while循环,如果试图输入超过buffer数组容量的字符,表达式pbuffer - bufffer等于BUFFER_LEN.当然如果输入一个刚好等于buffer数组容量的字符串,也会出现这种情况。所以也必须检查buffer的最后一个字符,确定它是不是'
'。如果不是,表示输入了太多的字符,所以在显示一个信息后,递减循环记为数器,进入下一次迭代。 |
|
1
|
下一条语句是: |
|
1
|
*(pbuffer - 1) = ' '; |
|
1
|
这条语句是把' '放在'
'字符的位置上,因为pbuffer指向buffer数组中第一个未用的元素。输入了字符串后,就使用malloc()函数请求足够的内存,保存这个字符串: |
|
1
|
pS[i] = (char*)malloc(pbuffer - buffer); |
|
1
|
if(pS[i] == NULL) |
|
1
|
{ |
|
1
|
printf("
Out of memory - ending program."); |
|
1
|
return 0; |
|
1
|
} |
|
1
|
所需的字节数是pbuffer当前指向的地址(即buffer中的第一个空元素)和buffer中第一个元素的地址之差。从malloc()返回的指针转换成char类型后,存储到pS数组的当前元素中。如果malloc()返回一个NULL指针,就显示一条信息,并结束程序。 |
|
1
|
使用下面的语句,把这个字符串从buffer复制到新得到的内存中: |
|
1
|
strcpy(pS[i],buffer); |
|
1
|
这条语句使用了库函数strcpy(),将buffer的内容复制到pS[i]指向的内存中。注意,使用strcpy()函数时不要混淆其参数。第二个参数是复制操作的源内容,第一个参数是目的地。混淆它们通常非常危险,因为复制操作会一直持续到找到' '为止。 |
|
1
|
结束循环后,不论是因为输入一个空字符串,或是使用了pS数组中的所有指针,都会产生输出: |
|
1
|
printf("
In reverse order,the strings you entered are:
"); |
|
1
|
while(--i >= 0) |
|
1
|
{ |
|
1
|
printf("
%s
", pS[i]); |
|
1
|
free(pS[i]); |
|
1
|
pS[i] = NULL; |
|
1
|
} |
|
1
|
索引i的值比输入字符串的个数多1。因此,在检查第一个循环条件后,可以使用它索引最后一个字符串。这个循环会递减这个值,在最后一次迭代时,i是0,索引第一个字符串。 |
|
1
|
可以使用表达式*(pS+i)代替pS[i],但使用数组表示法比较简洁。 |
|
1
|
在最后的printf()之后使用free()函数。这个函数和malloc()是互补的,它释放了malloc()分配的内存。它只需要把所分配的内存指针作为参数。虽然内存在程序结束后会自动释放,但是内存最好在不需要时立即释放。当然,一旦用这个方法释放在内存后,就不能再使用它,所以最好立刻将指针设定成NULL。 |
在这里,还要特别注意:
指针错误会产生灾难性的结果。如果使用一个没有指定地址值的未初始化指针存储值,该指针使用的地址就是存储在该指针位置的任何内容,这可能是内存中的任何一个位置。
好了,关于指针的内容先简单的说到这里。
指针的学习(四)——指针处理字符串-ZhouliS-ChinaUnix博客 http://blog.chinaunix.net/uid-26835614-id-3480657.html