c指针详解

发布 2019-08-05 19:40:57 阅读 8715

9.5 指针的应用(二)

指针可以方便地用来操作数组。

例题:写一程序,通过函数对一个int类型元素组成的数组按照插入法进行排序,然后输出。

插入法排序的基本思想是,把数据一个个地插入到一个有序的数组中。具体的实现可以用下面描述的方法进行。

首先数组被分为两个部分,已经排好序的部分和待插入的部分。显然只有一个元素时数组是有序的,所以一开始有序部分有一个元素,数组中其他部分都属于待插入部分。

例如,对于“int a=这个数组,最初有序部分和待插入部分分别为“”和“”。

然后每次从待插入部分拿出第一个插入到前面已经排好序的部分,这样排好序的部分就增加了一个元素,而待插入部分则减少了一个元素。最后当待插入部分没有任何元素时(dcr_tou < dcr_wei),则排序结束。这部分的功能由crpx()函数完成。

对于前面提到的数组来说,第一次插入意味着取出“9”插入到“”这个数组中适当的位置。第二次意味着把“7”插入到“”这个数组中……

把一个值(有序部分最后一个元素之后的元素即待插入部分的第一个元素)插入到一个有序数组中的解决过程是:首先把这个值与有序部分最后一个值进行比较,如果这个值大于等于有序部分最后一个值,则这个值的位置不动,插入结束。

以前面的数组为例,取出“9” 的值与“8”比较,由于9大于8,所以“9”应该在“8”的后面不动,插入结束。有序部分变为“”,待插入部分变为“”。下一步取出“7”与前面的“9”比较。

如果这个值小于有序部分最后一个元素,则把有序部分最后一个元素向后移动一个位置,这样成了少了一个元素有序部分的同样的问题,所以可以通过递归解决。这个部分由cr()函数解决。

也就是说,由于7小于9,所以“9”移动到后面一个位置(“7”原来所在的位置)。这时,问题就变成了将“7”插入到“”这个数组中合适位置的问题。显然这可以通过递归解决(“cr ( yx_tou , yx_wei - 1 , crz );

也就是说,由于7小于9,所以“9”移动到后面一个位置(“7”原来所在的位置)。这时,问题就变成了将“7”插入到“”这个数组中合适位置的问题。显然这可以通过递归解决(“cr ( yx_tou , yx_wei - 1 , crz );

程序**9-20

#include <>

#include <>

4. void crpx( int * int *

5. void cr( int * int * int )

6. void shuchu ( int * int *

8. int main( void )

12. crpx ( a , a + 1 )

13. shuchu( a , a + 1 )

15. system("pause");

16. return 0;

18. /输出数组。

19. void shuchu ( int * tou , int *wei )

29. putchar('');

32. /插入法排序。

33. /tou:数组开头;

34. /wei: 数组结尾(指向最后元素之后下一对象)

35. void crpx( int * tou , int *wei )

51. /把待插入值插入数组。

52. /因为待插入值在有序数组之后,53. /所以总可以 *(yx_wei+1) =yx_wei)

54. void cr( int * yx_tou , int * yx_wei , int crz )

61. *yx_wei + 1 ) yx_wei ;/把末尾元素向后移动一个位置。

63. if ( yx_tou ==yx_wei) /有序数组只有一个元素。

68. else

输出结果如图9-15所示。

图9-15 指针的应用。

在cr()函数中需要注意的是,其中的指针的最小值只能等于“a”,如果出现了小于“a”的情况,是一种未定义行为,这一点在写**时需要特别小心。指向数组元素的指针可以在数组所在的内存段上移动(最多到指向数组最后元素之后的第一个同类型对象),但不可以超过这个范围。可见,对于指针同样存在着“越界”的问题。

指向数组元素的指针可以通过加减法指向数组内部元素,或者数组后面第一个数据对象,超过这个范围则属于越界。当然,引用数组元素依然只能引用数组内部的。

9.6 高维数组名。

9.6.1 高维数组名是指针。

本节以二维数组为例,重点讲解高维数组的数组名的含义。如下定义了一个二维数组:

1. int a [2][3];

作为二维数组的数组名,“a”可以进行“运算(也就是可以进行一元“*”运算),所以显然“a”是一个指针。问题的重点在于其类型。

如图9-16所示,由于“*a”即“a[0]”本身是由3个“int”类型变量组成的一维数组“int [3]”,所以“a”是指向一个由3个“int”类型数据构成的一维数组的指针,这种类型在c语言中写做:

1. int (*3]

图9-16 二维数组名的含义之一。

下面**的输出证实了这一点。

程序**9-21

#include <>

#include <>

4. int main( void )

输出结果如图9-17所示。

图9-17 高维数组名是指针。

从输出结果可以看出,“&a[0][0]”与“a”的值相同,这表明这两个指针都始于同一个起点,也就是数组开始存储的第一个byte。然而“a+1”在数值上比“a”大“0022ff64 - 0022ff58 = c ”即十进制的12,说明“a”指向一大小为12byte的数据类型。最后3条的输出表明“*a”、“a[0]”及“int [3]”类型所占据的内存空间皆为12byte。

这就证实了“a”这个二维数组名是一个指向“int [3]”类型一维数组的指针,即“int (*3]”类型。

定义这种类型的指针变量的方法是:

1. int (*p_a)[3];

其中的“()是必需的,这是因为“的优先级比“*”要高,在说明“p_a”类型的时候,为了说明“p_a”首先与“*”相结合是一个指针变量,必须将“*p_a”用“()括起来以表明“p_a”是与“*”紧密结合。下面的定义则表示另一种含义:

1. int *a_p[3];

这里由于标识符“a_p”的前后有“*”和“两个类型说明符,而“的优先级别更高,因而“a_p”是一个数组名,“[中的“3”表示这个数组一共有3个元素,定义“int *a_p[3];”中的其他部分说明的是数组元素的类型,本例中数组“a_p”的3个元素皆为“int *”类型。

回到原来“a”的定义。现在已经分析出了“a”的类型是指向由3个“int”类型数据所构成的一维数组的指针,显然“a+1”也是同样类型的表达式,由于表达式“*(a+1)”等价于“a[1]”,所以它指向“a[1]”,而“a[1]”同样是一个“int [3]”类型的一维数组。

9.6.2 高维数组名是内存。

和一维数组名一样,在关于内存的运算中,二维数组名也代表这个二维数组所占据的那块内存。也就是说代表了一个数据对象(object)。

程序**9-22

#include <>

#include <>

4. int main(void)

6. int a [2][3];

7. int (*p) [2][3] =a ;

9. printf ("sizeof a = u" ,sizeof a);

10. printf ("a = p ,&a = p ,&a + 1 = p" ,a , a , a + 1 );

11. printf ("p = p ,p + 1 = p" ,p , p + 1 );

13. system("pause");

C语言所有复杂的指针声明

c语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法则其实并不是c标准里面的内容,它是从c标准的声明规定中归纳出来的方法。c标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左...

C语言经典算法详解

分而治之方法与软件设计的模块化方法非常相似。为了解决一个大的问题,可以 1 把它分成两个或多个更小的问题 2 分别解决每个小问题 3 把各小问题的解答组合起来,即可得到原问题的解答。小问题通常与原问题相似,可以递归地使用分而治之策略来解决。下列通过实例加以说明。例 利用分而治之算法求一个整数数组中的...

指针万用表工作原理

指针系仪表分为磁电式和电磁式两种,现在指针系仪表多数以磁电式仪表为主,根据磁路不同磁电式仪表又分为,内磁,外磁,内外磁,三种,所以讲解下磁电式仪表,其中外磁表头的指针万用表很容易受到外磁场的干扰而引起测量不准现象,所以外磁表头的指针万用表一般会在万用表后盖板上设计一块金属屏蔽板,金属屏蔽板的作用就是...