c语言之指针与数组知识点随笔

时间:2022-07-25
本文章向大家介绍c语言之指针与数组知识点随笔,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

   1、一元运算符*是间接寻址或间接引用运算符。  当它作用与指针时,将访问指针所指向的对象。

     2、&为地址运算符。它只能应用与内存中的对象,即变量与数组元素。它不能作用与表达式、常量或register类型的变量。

指针定义:

     指针是一种变量,它是保存变量地址的变量。

指针与地址

     通常机器都有一系列的连续编号或编址的存储单元,这些存储单元可以单个进行操纵,也可以连续成组的方式进行操纵。通常情况下,机器的一个字节可以存放一个char类型的数据,两个相邻的字节存储单元可存储一个short(短整型)类型的数据,而4个相邻的字节存储单元便可存储一个long(长整型)类型的数据。指针是能够存放一个地址的一组存储单元(通常为两个或四个字节)。

简单示例:

1 int a = 1, b = 2, c[10];
2 int *p;            /* p是指向int类型的指针 */
3 p = &a;          /* p现在指向a */
4 b = *p;          /* b的值现在为1 */
5 *p = 0;          /* a的值现在为0 */
6 p = &c[0];     /* p现在指向c[0] */

注意:

    指针只能指向某种特定类型的对象,也就是说,每个指针都必须指向某种特定的数据类型。而void类型的指针则可以存放指向任何类型的指针,但它不能引用自身。

运算符优先级:

     一元运算符*和&的优先级比算术运算符的优先级要高。形如a = *p + 1则执行*p指向的对象的值取出并加1操作,然后再将结果赋值给a。而*p += 1则是将p指向的对象的值加1。

*p += 1 <=>++*p或(*p)++  一元运算符遵循从右至左的结合顺序。

最后补充一点:

     由于指针也是变量,所以在程序中可以直接使用,而不必通过间接引用的方法使用。

指针与函数参数

     由于c语言是以传值的方式将参数值传递给被调用函数,因此被调用函数不能直接修改主调用函数中变量的值,即使要修改,也只是修改了变量参数副本的值。

 1 /*  这是一个错误的示例 */
 2 void swap(int x, int y)
 3 {
 4      int temp;
 5      temp = x;
 6      x = y;
 7      y = temp;
 8 }
 9 
10 /* 这个是正确的示例,使用了指针来达到我们所需要的功能 */
11 void swap(int *px, int *py)
12 {
13      int temp;
14      temp = *px;
15      *px = *py;
16      *py = temp;
17 }

指针与数组

      在c语言中指针与数组的关系十分密切,通过数组下标所能完成的任何操作通过指针都可以实现。用指针编写的程序要比用数组下标编写的程序执行速度快。

int a[10];先定义一个长度为10的数组a,即由10个对象组成的集合,这10个对象存储在相邻的内在区域中,名字分别为a[0]、a[1]...a[9]。a[i]可 表示为该数组的第i个元素。

int *pa;此处声明了一个指向整型类型的指针,

pa = &a[0];则表示pa指向数组a的第0个元素,也就是说pa的值为数组a[0]的地址。

x = *pa;将数组a[0]中的内容复制到变量x中。

如果pa指向数组中某个特定元素pa = &a[i],那么,pa+1将指向下一个元素,pa+i将指向数组当前之后的第i个元素,而pa-i将指向当前数组元素之前的第i个元素。

因此,如果pa指向a[0],那么*(pa+i)引用的是数组a[i]的内容,pa+i存储的是数组元素a[i]的地址。

执行pa = &a[0];后,pa和a具有相同的值,因为数组名所代表的就是该数组最开始的一个元素的地址,所以pa = &a[0] <=> pa = a 而对数组元素a[i]的引用也可以写成*(a+i)。

实际上在c语言中计算a[i]的值时,首先是将其转换成*(a+i)的形式,然后再求值。如果对这两种等价的表示形式分别加地址运算符&,可以知道:&a[i]和a+i的含义是相同的。

总结:

     一个通过数组和下标实现的表达式可等价地通过指针或偏移量实现。指针是一个变量,因此在c语言中,pa = a和pa++都是合法的。但数组名不是变量,因此类似a = pa和a++形式的语句都是非法的。

当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址。在被调用函数中,该参数是一个局部变量,因此,数组名参数必须是一个指针,也就是一个储存地址值的变量。

1 /* strlen函数:返回字符串s的长度 */
2 int strlen(char *s)
3 {
4        int n;
5        for (n = 0; *s != ''; s++)
6              n++;
7        return n;
8 }

上例中,s是一个指针,所以对其执行自增运算是合法的。指向s++不会影响到strlen函数的调用者中的字符串,它仅对该指针在strlen函数中的私有副本进行自增运算。

地址算术运算

     如果p是一个指向数组中某个元素的指针,那么p++将对p进行自增运算并指向下一个元素,而p+=i将对p进行加i的增量运算,使其指向指针p当前所指向的元素之后的第i个元素。这类运算是指针或地址运算中最简单的形式。

     c语言中的地址运算方法是一致且有规律的,将指针、数组和地址的算法运算集成在一起是c语言的一大优点。

看下面的并不完善的分配存储程序:它是由2个函数组成。第一个函数alloc(n)返回一个指向n个连续字符存储单元的指针,alloc函数的调用者可利用该指针存储字符序列。第二个函数afree(p)释放已分配的存储空间,以便以后重用。之所以说这两个函数是“不完善的”,是因为afree函数的调用次序必须与调用alloc函数的次序相反。换句话说,alloc与afree以栈的方式(即后进先出的列表)进行存储空间管理。

实现方法:先是让alloc函数对一个大字符数组allocbuf中的空间进行分配。该数组是alloc和afree两个函数私有的数组。由于函数alloc和afree处理的对象是指针不是数组下标,因此,调用函数无需知道该数组的名字,这样,可以在包含alloc和afree的源文件中将该数组声明为static类型,使得它对外不可见。实际实现时,该数组甚至可以没有名字,它可以通过调用alloc函数或向操作系统申请一个指向无名存储块的指针来获得。

allocbuf中的空间使用状况也是我们需要了解的信息。我们使用指针allocp指向allocbuf中的下一个空闲单元。当调用alloc申请n个字符的空间时,alloc检查allocbuf数组中有没有足够的剩余空间。如果有足够的剩余空间,则alloc返回allocp的当前值(即空闲块的开始位置),然后将allocp加n以使它指向下一个空闲区域。如果空闲空间不够,则alloc返回0。如果p在alocbuff的边界之内,则afree(p)仅仅只是将allocp的值设为p。

 1 #define ALLOCSIZE 1000 /*  可用空间大小 */
 2 
 3 static char allocbuff[ALLOCSIZE];  /*  alloc使用的存储区 */
 4 
 5 static char *allocp = allocbuff;       /*  下一个空闲位置 */
 6 
 7 char *alloc(int n)    /* 返回指向n个字符的指针 */
 8 {
 9        if (allocbuff + ALLOCSIZE - allocp >= n) { /* 有足够的空间 */
10              allocp += n;
11              return allocp - n;
12        } else {     /* 空间不够 */
13              return 0;
14        }
15 }
16 
17 void afree(char *p)    /*  释放p指向的存储区 */
18 {
19        if (p >= allocbuff && p < allocbuff + ALLOCSIZE)
20                allocp = p;
21 }

一般情况下,同其他类型的变量一样,指针也可以初始化。通常,对指针有意义的初始化值只能是0或者表示地址的表达式,对后者来说,表达式所代表的地址必须是在此前已定义的具有适当类型的数组的地址。

      指针与整数之间不能相互的转换,但0是唯一的例外:常量0可以赋值给指针,指针也可以常量0进行比较。程序中常用符号常量NULL代替常量0,这样便于清晰的说明常量0是指针的一个特殊值。

使用指针的减法运算来编写函数strlen的另一个版本。

View Code 

1 /*  strlen函数:返回字符串s的长度 */
2 int strlen(char *s)
3 {
4       char *p = s;
5       while (*p != '')
6             p++;
7       return p - s;
8 }

在上述的程序段中,指针p被初始化为指向s,即指向该字符串的第一个字符。while循环语句将依次检查字符串中的每个字符,直到遇到标识符数组结尾的字符‘’为止。p是指向字符的指针,所以每执行一次p++,p就将指向下一个字符的地址,p-s则表示已经检查过的字符数,即字符串的长度。

      有效的指针运算符包括:1、相同类型的指针之间的运算;2、指向同整数之间的加法或减法运算;3、指向相同数组中元素的两个指针间的减法或比较运算;4、将指针赋值为0或指针与0之间的比较运算。