指针*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
posted @ 2017-08-29 16:55  ostartech  阅读(1319)  评论(0编辑  收藏  举报