Chinaunix首页 | 论坛 | 博客
  • 博客访问: 42163
  • 博文数量: 7
  • 博客积分: 76
  • 博客等级: 民兵
  • 技术积分: 105
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-29 20:03
文章分类

全部博文(7)

文章存档

2013年(7)

我的朋友

分类: C/C++

2013-01-23 20:15:57

1、指针处理字符串

我们可以用char类型的数组变量存储字符串,也可以使用char类型的指针变量引用字符串。这个方法在处理字符串时非常灵活。如下所示:

char *pString = NULL;

注意,指针只是一个存储另一个内存位置的地址变量。前面只创建了指针,没有指定一个存储字符串的地方。要存储字符串,需要分配一些内存。可以声明一块内存,来存储字符串数据,然后使用指针追踪这块存储字符串的内存。

1、使用指针更多的控制字符串输入

在读取文本时,常需要比scanf()函数更多的控制。在中声明的getchar()函数提供了非常基本的操作,一次只读取一个字符,但是它可控制何时停止读入字符。这样就可以确保不会超过存储输入而分配的内存。

getchar()函数从键盘读入一个字符,并以int类型返回。可以把一个结尾‘\n'的字符串读入所定义的数组中。如下

char buffer[100];

char *pbuffer = buffer;

while((*pbuffer++ = getchar() != '\n');

*pbuffer = '\0';

所有的输入都在while循环的条件中完成。getchar()函数读取一个字符,并它存储在pbuffer的当前地址中。然后,递增pbuffer中的地址,以指向下一个字符。在循环结束后,将'\0'字符添加到下一个可用的位置上。

2、使用指针数组

处理多个字符串时,可以在堆上使用指针数组存储对字符串的引用。下面用一个例子来说明


#include 
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;
}
      结束输出如下:



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,才能用来指定数组大小;数组的大小只能用常量式来指定。

接着就是主函数定义


char buffer[BUFFER_LEN];
  char *pS[3] = { NULL };
  char *pbuffer = buffer;
  size_t index = 0;
  int i;
buffer数组的类型是char,有BUFFER_LEN个元素。pS数组有3个指针存储buffer数组中字符串的地址。pbuffer指针用buffer数组中的第一个字节的地址初始化在输入字符时,要用pbuffer遍历buffer数组。index变量记录buffer数组中当前未使用的元素位置。
第一个for循环读取3个字符串。循环中的第一条语句如下:
printf("\nEnter %s message\n", i >0 ? "another" : "a");
这里通过一种简洁的方式使用条件运算符,在for循环的第一次迭代后修改提示。
该语句在第一次迭代时输出a,在后续的迭代中输出;another。
下一条语句将当前保存在pbuffer中的地址存储到指针数组中:
pS[i] = &buffer[index];
上述赋值语句把指针pbuffer中的地址保存到指针数组pS的一个元素中
读取字符串并添加字符串终止符的语句如下:
for(; index < BUFFER_LEN; index++)
  if((*(pbuffer + index) = getchar()) == '\n';
    {
      *(pbuffer + index++) = '\0';
      break;
    }
这个for循环就是用于读取到buffer数组未尾的循环。如果读入一个'\n'就用'\0'替代它,并结束循环结束后,检查bffer数组是否还没有达到字符串的未尾就已满:
if((index == BUFFER_LEN) && ((*(pbuffer + index - 1) != '\0') || (i < 2)))
{
  printf("\nYou ran out of space in the buffer.")
  return 1;
}
使用getchar()读取字符串,可以对输入过程进行很多控制。这种方法并不ur公限于读取字符串,还可以用于读取逐个处理字符串的所有输入过程。可以从输入中删除空格,或者查找特定的字符,例如用于分隔各个输入值的逗号。
printf("\nThe string you entered are:\n\n");
for(i = 0; i < 3; i++)
  printf("%s\n", pS[i]);
在循环中,输出pS指向的每一个元素中的字符串。
在最后一个printf()中,输出字符串中剩下的字符个数:
printf("The buffer has %d characters unused.\n", BUFFER_LEN - index);
从buffer数组的元素个数中减去index,得到未使用的元素个数
下面来修改一下这个程序让它实现输入任意个字符串:

#include 
#include 
#include 
#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;
}
输出的结果如下:

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
这个代码与上一个相比,这个程序稍有扩展,但涵盖了相当多的内容。现在可以处理任意数量的字符串,能处理的最大字符串是数组pS中的指针数。这个数组的大小在程序起始定义,以便于修改。
#define NUM_P 100;  (这个是gcc编译器下的,也可以是const size_t NUM_P = 100;)
只要修改这个数字就可以改变这个程序能处理的最大的字符串数。在main()函数中声明如下:

char buffer[BUFFER_LEN];
  char *pS[NUM_P] = { NULL };
  char *pbuffer = buffer;
  int i = 0;
buffer数组只是一个输入缓冲区,含有每个读入的字符串。因此#define指令将BUFFER_LEN定义为能接受的字符串最大长度。然后,声明指针数组的长度NUM_P和指针puffer,以用于buffer数组。最后是两个循环控制变量。
下面显示一条信息,说明输入的限制:

printf("\\nYou can enter up to %u message each up to %u characters.", NUM_P, BUFFER_LEN - 1);
输入信息的最大长度允许加上终止字符。
第一个for循环读入字符串并存储它们。这个循环控制如下:
for(i = 0; i < NUM_P; i++)
这能确保输入的字符串不超过前面声明的指针数量。一旦输入的字符串数到达最大字符串数,循环就会结束,进入程序的输出部分。
在循环中,字符串输入使用类似getchar()的机制,但是多了一个额外的条件:
while((pbuffer - buffer < BUFFER_LEN - 1) && ((*pbuffer++ = getchar()) != '\n'));
整个过程发生在while循环的条件式中。由getchar()得到的字符存储在pbuffer指向的地址中,pbuffer最初保存的是buffer的地址。然后递增pbuffer指针,指向下一个可用的空间,这个赋值语句所存储的字符与'\n'比较,若该字符是'\n',就结束循环。如果pbuffer - buffer < BUFFER_LEN - 1 是false,循环也会结束。即如果下一个要存储的字符占据了buffer数组的最后一个位置,循环也会结束。
输入过程结束后,用下面的语句进行检查:
if((pbuffer = buffer) < 2)
  break;
这个语句检测空行,因为如果只按下回车键,就只输入一个字符'\n'。此时,break语句立即结束循环,开始输出过程。
下一个if语句检查是否试图输入超过buffer容量的字符串:
if((pbuffer - buffer) == BUFFER_LEN && *(pbuffer - 1) != '\n')
{
  printf("String too long - maxmum %d character allowed.", BUFFER_LEN);
  i--;
}
因为使用了buffer数组的最后一个位置时,会结束while循环,如果试图输入超过buffer数组容量的字符,表达式pbuffer - bufffer等于BUFFER_LEN.当然如果输入一个刚好等于buffer数组容量的字符串,也会出现这种情况。所以也必须检查buffer的最后一个字符,确定它是不是'\n'。如果不是,表示输入了太多的字符,所以在显示一个信息后,递减循环记为数器,进入下一次迭代。
下一条语句是:
*(pbuffer - 1) = '\0';
这条语句是把'\0'放在'\n'字符的位置上,因为pbuffer指向buffer数组中第一个未用的元素。输入了字符串后,就使用malloc()函数请求足够的内存,保存这个字符串:
pS[i] = (char*)malloc(pbuffer - buffer);
if(pS[i] == NULL)
{
  printf("\nOut of memory - ending program.");
  return 0;
}
所需的字节数是pbuffer当前指向的地址(即buffer中的第一个空元素)和buffer中第一个元素的地址之差。从malloc()返回的指针转换成char类型后,存储到pS数组的当前元素中。如果malloc()返回一个NULL指针,就显示一条信息,并结束程序。
使用下面的语句,把这个字符串从buffer复制到新得到的内存中:
strcpy(pS[i],buffer);
这条语句使用了库函数strcpy(),将buffer的内容复制到pS[i]指向的内存中。注意,使用strcpy()函数时不要混淆其参数。第二个参数是复制操作的源内容,第一个参数是目的地。混淆它们通常非常危险,因为复制操作会一直持续到找到'\0'为止。
结束循环后,不论是因为输入一个空字符串,或是使用了pS数组中的所有指针,都会产生输出:
printf("\nIn reverse order,the strings you entered are:\n");
while(--i >= 0)
{
  printf("\n%s\n", pS[i]);
  free(pS[i]);
  pS[i] = NULL;
}
索引i的值比输入字符串的个数多1。因此,在检查第一个循环条件后,可以使用它索引最后一个字符串。这个循环会递减这个值,在最后一次迭代时,i是0,索引第一个字符串。
可以使用表达式*(pS+i)代替pS[i],但使用数组表示法比较简洁。
在最后的printf()之后使用free()函数。这个函数和malloc()是互补的,它释放了malloc()分配的内存。它只需要把所分配的内存指针作为参数。虽然内存在程序结束后会自动释放,但是内存最好在不需要时立即释放。当然,一旦用这个方法释放在内存后,就不能再使用它,所以最好立刻将指针设定成NULL。


在这里,还要特别注意:

指针错误会产生灾难性的结果。如果使用一个没有指定地址值的未初始化指针存储值,该指针使用的地址就是存储在该指针位置的任何内容,这可能是内存中的任何一个位置。


好了,关于指针的内容先简单的说到这里。

阅读(9699) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~