指针*pbuffer和getchar 读取字符串
在C语言入门教材里看到这一段代码,没看懂是什么意思。
char buffer[10];
char *pbuffer = buffer;
while( (*pbuffer++ = getchar() )!= '\n');
*pbuffer = '\0';
尤其是第三段while( (*pbuffer++ = getchar() )!= '\n'); 这里的getchar取的是什么数据,是我输入的数据吗?*pbuffer是一个指针数组吗,是不是存了输入的所有信息?
*buffer不是指针数组,是一个字符型的指针,让指针pbuffer指向了数组buffer的首地址,那么*pbuffer就跟buffer[0]是等价的,而pbuffer++的意思就是让pbuffer指向当前所指的下一个单元。也就是说执行完pbuffer++以后,*pbuffer就和buffer[1]等价。
while( (*pbuffer++ = getchar() )!= '\n');的作用是读取输入的字符到buffer中,遇到换行符停止读取。
getchar的意思是读取一个字符变量并返回,
那这段代码执行完之后,*pbuffer这个指针存的是什么内容?
未知的。
执行完*pbuffer = getchar()后 pbuffer又自加了一次,此时pbuffer是指向的地址是'\n'的下一个元素的地址,而这个值你的代码里边并没有给出结果,所以是未知的。
指针的学习(四)——指针处理字符串
1、指针处理字符串
我们可以用char类型的数组变量存储字符串,也可以使用char类型的指针变量引用字符串。这个方法在处理字符串时非常灵活。如下所示:
char *pString = NULL;
注意,指针只是一个存储另一个内存位置的地址变量。前面只创建了指针,没有指定一个存储字符串的地方。要存储字符串,需要分配一些内存。可以声明一块内存,来存储字符串数据,然后使用指针追踪这块存储字符串的内存。
1、使用指针更多的控制字符串输入
在读取文本时,常需要比scanf()函数更多的控制。在<stdio.h>中声明的getchar()函数提供了非常基本的操作,一次只读取一个字符,但是它可控制何时停止读入字符。这样就可以确保不会超过存储输入而分配的内存。
getchar()函数从键盘读入一个字符,并以int类型返回。可以把一个结尾‘\n'的字符串读入所定义的数组中。如下
char buffer[100];
char *pbuffer = buffer;
while((*pbuffer++ = getchar() != '\n');
*pbuffer = '\0';
所有的输入都在while循环的条件中完成。getchar()函数读取一个字符,并它存储在pbuffer的当前地址中。然后,递增pbuffer中的地址,以指向下一个字符。在循环结束后,将'\0'字符添加到下一个可用的位置上。
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 message Hello C Enter another message Today is a great day for learngin Enter another message so start len The string you entered are: Hello C Today is a great day for learngin so start len The 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 ( "\nEnter %s message\n" , 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 ()) == '\n' ; |
1
|
{ |
1
|
*(pbuffer + index++) = '\0' ; |
1
|
break ; |
1
|
} |
1
|
这个 for 循环就是用于读取到buffer数组未尾的循环。如果读入一个 '\n' 就用 '\0' 替代它,并结束循环结束后,检查bffer数组是否还没有达到字符串的未尾就已满: |
1
|
if ((index == BUFFER_LEN) && ((*(pbuffer + index - 1) != '\0' ) || (i < 2))) |
1
|
{ |
1
|
printf ( "\nYou ran out of space in the buffer." ) |
1
|
return 1; |
1
|
} |
1
|
使用 getchar ()读取字符串,可以对输入过程进行很多控制。这种方法并不ur公限于读取字符串,还可以用于读取逐个处理字符串的所有输入过程。可以从输入中删除空格,或者查找特定的字符,例如用于分隔各个输入值的逗号。 |
1
|
printf ( "\nThe string you entered are:\n\n" ); |
1
|
for (i = 0; i < 3; i++) |
1
|
printf ( "%s\n" , pS[i]); |
1
|
在循环中,输出pS指向的每一个元素中的字符串。 |
1
|
在最后一个 printf ()中,输出字符串中剩下的字符个数: |
1
|
printf ( "The buffer has %d characters unused.\n" , 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 = "brush:cpp;" >#include <stdio.h> #include <stdlib.h> #include <string.h> #define NUM_P 100 const 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 = "brush:cpp;" >输出的结果如下:</pre> <pre class = "brush:cpp;" > <pre class = "brush:cpp;" >You can enter up to 100 message each up to 127 characters. Enter a message, or press Enter to end 12344555;34344 Enter another message, or press Enter to end zidfjdjfadifda Enter another message, or press Enter to end fdfjdjfdsa Enter another message, or press Enter to end In reverse order, the string you entered are: fdfjdjfdsa zidfjdjfadifda 12344555;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 = "brush:as3;" > char buffer[BUFFER_LEN]; char *pS[NUM_P] = { NULL }; char *pbuffer = buffer; int i = 0;</pre> <pre class = "brush:as3;" >buffer数组只是一个输入缓冲区,含有每个读入的字符串。因此#define指令将BUFFER_LEN定义为能接受的字符串最大长度。然后,声明指针数组的长度NUM_P和指针puffer,以用于buffer数组。最后是两个循环控制变量。</pre> |
1
|
下面显示一条信息,说明输入的限制: |
1
2
3
4
5
6
7
8
|
<pre class = "brush: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 = "brush:cpp;" style= "text-indent:24px;" >输入信息的最大长度允许加上终止字符。</pre> <pre class = "brush:cpp;" style= "text-indent:24px;" >第一个 for 循环读入字符串并存储它们。这个循环控制如下:</pre> <pre class = "brush:cpp;" style= "text-indent:24px;" > for (i = 0; i < NUM_P; i++)</pre> <pre class = "brush:cpp;" style= "text-indent:24px;" >这能确保输入的字符串不超过前面声明的指针数量。一旦输入的字符串数到达最大字符串数,循环就会结束,进入程序的输出部分。</pre> <pre class = "brush:cpp;" style= "text-indent:24px;" >在循环中,字符串输入使用类似 getchar ()的机制,但是多了一个额外的条件:</pre> <pre class = "brush:cpp;" style= "text-indent:24px;" > while ((pbuffer - buffer < BUFFER_LEN - 1) && ((*pbuffer++ = getchar ()) != '\n' ));</pre> <pre class = "brush:cpp;" style= "text-indent:24px;" >整个过程发生在 while 循环的条件式中。由 getchar ()得到的字符存储在pbuffer指向的地址中,pbuffer最初保存的是buffer的地址。然后递增pbuffer指针,指向下一个可用的空间,这个赋值语句所存储的字符与 '\n' 比较,若该字符是 '\n' ,就结束循环。如果pbuffer - buffer < BUFFER_LEN - 1 是 false ,循环也会结束。即如果下一个要存储的字符占据了buffer数组的最后一个位置,循环也会结束。</pre> |
1
|
输入过程结束后,用下面的语句进行检查: |
1
|
if ((pbuffer = buffer) < 2) |
1
|
break ; |
1
|
这个语句检测空行,因为如果只按下回车键,就只输入一个字符 '\n' 。此时, break 语句立即结束循环,开始输出过程。 |
1
|
下一个 if 语句检查是否试图输入超过buffer容量的字符串: |
1
|
if ((pbuffer - buffer) == BUFFER_LEN && *(pbuffer - 1) != '\n' ) |
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的最后一个字符,确定它是不是 '\n' 。如果不是,表示输入了太多的字符,所以在显示一个信息后,递减循环记为数器,进入下一次迭代。 |
1
|
下一条语句是: |
1
|
*(pbuffer - 1) = '\0' ; |
1
|
这条语句是把 '\0' 放在 '\n' 字符的位置上,因为pbuffer指向buffer数组中第一个未用的元素。输入了字符串后,就使用 malloc ()函数请求足够的内存,保存这个字符串: |
1
|
pS[i] = ( char *) malloc (pbuffer - buffer); |
1
|
if (pS[i] == NULL) |
1
|
{ |
1
|
printf ( "\nOut 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 ()函数时不要混淆其参数。第二个参数是复制操作的源内容,第一个参数是目的地。混淆它们通常非常危险,因为复制操作会一直持续到找到 '\0' 为止。 |
1
|
结束循环后,不论是因为输入一个空字符串,或是使用了pS数组中的所有指针,都会产生输出: |
1
|
printf ( "\nIn reverse order,the strings you entered are:\n" ); |
1
|
while (--i >= 0) |
1
|
{ |
1
|
printf ( "\n%s\n" , 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
指针*pbuffer和getchar 读取字符串的更多相关文章
- C语言——常用标准输入输出函数 scanf(), printf(), gets(), puts(), getchar(), putchar(); 字符串拷贝函数 strcpy(), strncpy(), strchr(), strstr()函数用法特点
1 首先介绍几个常用到的转义符 (1) 换行符“\n”, ASCII值为10: (2) 回车符“\r”, ASCII值为13: (3) 水平制表符“\t”, ASCII值为 9 ...
- 常见错误0xCCCCCCCCC 读取字符串的字符时出错及其引申。
问题描述在一个函数调用中,使用二级指针作为函数参数,传递一个字符串指针数组,但是在访问的时候,却出现了运行时错误,具体表现为"0xCCCCCCCC 读取字符串的字符时出错". 第一 ...
- 关于C中scanf()函数读取字符串的问题
#include <stdio.h> int main(void) { ]; scanf("%s", s_name); printf("Hello, %s!\ ...
- f-stack中ipc传递指针从应用中读取信息时挂掉
f-stack中ipc传递指针从应用中读取信息时挂掉 如:创建bridge0./ifconfig bridge0 create./ifconfig f-stack-0 down./ifconfig f ...
- 如何使用App.config文件,读取字符串?
如何使用App.config文件,读取字符串? .在项目里添加App.config文件,内容如下: <?xml version="1.0" encoding="ut ...
- java保存json格式数据,保存字符串和读取字符串
1.java保存json格式数据,保存字符串和读取字符串 import java.io.*; class RWJson { public void wiite(String s, String toS ...
- C++读取字符串数据的两种方式
C++读取字符串数据的两种方式 对于同样的样例输入: ladder came tape soon leader acme RIDE lone Dreis peat ScAlE orb eye Ride ...
- Python从文件中读取字符串,用正则表达式匹配中文字符的问题
2013-07-27 21:01:37| 在Windows下,用Python从.txt文件中读取字符串,并用正则表达式匹配中文,在网上看了方法,用的时候发现中文没有被匹配. ...
- java读取字符串,生成txt文件
/** * 读取字符串,生成txt 文件 已解决未设置编码时,在项目中直接打开文件,中文乱码问题 * WriteText.writeToText(musicInfo,fileName)直接调用 * * ...
随机推荐
- 〖Linux〗通过USB连接,共享Linux上的网络,使用Android手机上网。
1. Android手机上打开USB共享 2. Linux上修改USB0的ip地址并启用 sudo ifconfig usb0 192.168.42.127 up 3. Android手机上修改路由表 ...
- jquery获取json对象中的key小技巧,遍历json串所有key,value
比如有一个json var json = {"name" : "Tom", "age" : 18}; 想分别获取它的key 和 value ...
- 分享阿里云SLB-负载均衡的实现基本原理架构
负载均衡技术原理浅析 https://help.aliyun.com/knowledge_detail/39444.html?spm=5176.7839438.2.6.XBbX5l 阿里定制版的LVC ...
- myql基准测试工具Sysbench
一.Sysbench介绍 SysBench是一个模块化的.跨平台.多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况.它主要包括以下几种方式的测试: 1.cpu性能 2.磁盘io性 ...
- 使用vs调试.net源代码
使用.NET Framework库参考源进行调试 您可能会想知道使用.NET Framework参考源的调试方式.在下面的示例中,您将看到一个我调用公用Console.WriteLine方法的工具.从 ...
- HTTP标头信息
HTTP头信息头信息由“键:值”组成.它们描述客户端或者服务器的属性.被传输的资源以及应该实现连接. 四种不同类型的头标 通用头标:即可用于请求,也可用于响应,是作为一个整体而不是特定资源与事务相关联 ...
- js身份证验证算法
var validateIdCard=function (id, backInfo) { var info={ y: "1900", m: "01", d: & ...
- Error-Project facet Java version 1.8 is not supported
最近导入最新的Strtus2.5.10.1 Demo时出现了这个错误 解决方案如下: 选中工程——右键——Properties 然后依次展开找到如图所示内容,将1.8改成1.7即可. 原因:工程默认配 ...
- PL/SQL developer连接oracle出现“ORA-12154:TNS:could not resolve the connect identifier specified”问题的解决
转载请注明出处:http://blog.csdn.net/dongdong9223/article/details/50728536 本文出自[我是干勾鱼的博客] 使用PL/SQL developer ...
- python生成器,函数,数组
1.什么是生成器用一个比喻来形容,工厂中生产保龄球的流水线,机器每次只生产一个保龄球,下次继续生产下一个,直到停止(原料不足,停止供电等条件)为止.机器就是我们的生成器. 2.使用示例在python中 ...