C Primer Plus 指针专题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_20440225/article/details/79846413

#include<stdio.h>

int main(void)

{

         int urn[5] = { 100, 200, 300, 400, 500};

         int *ptr1, *ptr2, *ptr3;

 

         ptr1 = urn;                  //把一个地址赋给指针

         ptr2 = &urn[2]; //把一个地址赋给指针

 

         //解引用指针,以及获得指针的地址

         printf("pointer value,dereferenced pointer, pointer address: \n");

         printf("ptr1 = %p, *ptr1 = %d,&ptr1 = %p\n", ptr1, *ptr1, &ptr1);

 

         //指针加法

         printf("\nadding an int to apointer?:\n");

         printf("ptr1 + 4 = %p, *(ptr1 + 4)= %d\n", ptr1 + 4, *(ptr1 + 4));

         ptr1++; //递增指针

         printf("\nvalues afterptr1++:\n");

         printf("ptr1 = %p, *ptr1 = %d,&ptr1 = %p\n", ptr1, *ptr1, &ptr1);

         ptr2--; //递减指针

         printf("\bvalues after--ptr2:\n");

         printf("ptr2 = %p, *ptr2 = %d,&ptr2 = %p\n", ptr2, *ptr2, &ptr2);

         --ptr1; //恢复为初始值

         ++ptr2; //恢复为初始值

         printf("\nPointers reset tooriginal values:\n");

         printf("ptr1 = %p, ptr2 =%p\n", ptr1, ptr2);

         //一个指针减去另一个指针

         printf("\nsubtracting one pointerfrom anoter: \n");

         printf("ptr2 = %p, ptr1 = %p, ptr2- ptr1 = %d\n", ptr2, ptr1, ptr2 - ptr1);

         //一个指针减去一个整数

         printf("\nsubtracting an int froma pointer:\n");

         printf("ptr3 = %p, ptr3 - 2 =%p\n", ptr3, ptr3 - 2);

         return 0;
}

/*

         赋值:可以把地址赋给指针,地址要和指针类型兼容。

         可以使用数组名、带地址运算符(&)的变量名、另一个指针进行赋值。

         解引用: *运算符给出指针指向地址上储存的值。*ptr1的初值是100,该值储存在编号为00BEFCB0的地址上。

         取址:和所有变量一样,指针变量也有自己的地址和值。对指针而言,&运算符给出指针本身的地址。

                   本例中,ptr1 储存在内存编号为00BEFCA4的地址上,该存储单元储存的内容是00BEFCB0,即urn的地址。因此&ptr1是指向ptr1的指针,而ptr1是指向utn[0]的指针。

         指针与整数相加:可以使用+运算符把指针与整数相加,或整数与指针相加。无论哪种情况,整数都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相加。

         递增指针:递增指向数组元素的指针可以让该指针移动至数组的下一个元素。

         指针减去一个整数:可以使用-运算符从一个指针中减去一个整数。

         递减指针:当然,除了递增指针还可以递减指针。

         指针求差:可以计算两个指针的差值。通常,求差的两个指针分别指向同一个数组的不同元素,通过计算求出两元素之间的距离。差值的单位与数组类型的单位相同。

         比较:使用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。

         注意:减法有两种。可以用一个指针减去另一个指针得到一个整数,或者用一个指针减去一个整数得到另一个指针。

         一定要牢记一点千万不要解引用未初始化的指针。例如,考虑下面的例子:

                   int * pt;     // 未初始化的指针

                   *pt = 5;   // 严重的错误

         切记:创建一个指针时,系统只分配了储存指针本身的内存,并未分配储存数据的内存。因此,在使用指针之前,必须先用已分配的地址初始化它。

         C 程序员创建了指针数组、函数指针、指向指针的指针数组、指向函数的指针数组等。

保护数组中的数据:

         处理基本类型(如,int)的函数时,要选择是传递int类型的值还是传递指向int的指针。

         通常都是直接传递数值,只有程序需要在函数中改变该数值时,才会传递指针。

         对于数组别无选择,必须传递指针,因为这样做效率高。

         如果一个函数按值传递数组,则必须分配足够的空间来储存原数组的副本,然后把原数组所有的数据拷贝至新的数组中。

         如果把数组的地址传递给函数,让函数直接处理原数组则效率要高。

         传递地址会导致一些问题。

         C 通常都按值传递数据,因为这样做可以保证数据的完整性。

*/

#include<stdio.h>

#defineSIZE 5

void show_array(const double ar[], int n);

void mult_array(double ar[], int n, double mult);

intmain(void)

{

         double dip[SIZE] = { 20.0, 17.66, 8.2,15.3, 22.22 };

         printf("The original diparray:\n");

         show_array(dip, SIZE);

         mult_array(dip, SIZE, 2.5);

         printf("The dip array aftercalling mult_array():\n");

         show_array(dip, SIZE);

         return 0;

}

/*-- 显示数组内容 --*/

voidshow_array(const double ar[], int n)

{
         int i;
         for (i = 0; i < n; i++)
             printf("%8.3f  ", ar[i]);
         putchar('\n');
}

/*-- 把数组的每个元素都乘以相同的值 --*/

voidmult_array(double ar[], int n, double mult)

{
     int i;

     for (i = 0; i < n; i++)
        ar[i] *= mult;

}

/*

         const不是要求原数组是常量,而是该函数在处理数组时将其视为常量,不可更改。

         使用const可以保护数组的数据不被修改,就像按值传递可以保护基本数据类型不被改变一样。

         指向const的指针不能用于改变值。       

  double rates[5] = {88.99, 100.12, 59.45, 183.11, 340.5};
  const double * pd = rates;  // pd指向数组的首元素

         第2行代码把pd指向的double类型的值声明为const,这表明不能使用pd来更改它所指向的值:

                  

 *pd = 29.89;   // 不允许

 pd[2] = 222.22;  //不允许

 rates[0] = 99.99; // 允许,因为rates未被const限定

 int sum(int * ar, int n) //通用方法
  {
       int i;
       int total = 0;

       for(i = 0; i < n;i++) //使用N个元素
           total +=ar[i];
        return total;
   }

         第一个形参告诉函数该数组的地址个数据类型;第二个形参告诉函数该数组中元素的个数。

         注意:只有在函数原型或函数定义头中,才可以用int ar[]代替int * ar。

 int sum(int ar[], int n);

         int *ar形式和int ar[]形式都表示ar是一个指向int的指针。

         区别:int ar[]只能用于声明形式参数。

         int ar[]表明指针ar指向的不仅仅是一个int类型的值,还有int类型数组的元素。

         下面四种原型是等价的:                         

 int sum(int *ar, intn);
 int sum(int *, int);
 int sum(int ar[],int n);
 int sum(int [],int);

         在函数定义中不能省略参数名。下面两种形式的函数定义等价:

                           

 int sum(int *ar, intn);
 {
       ......
  }

 int sum(int ar[],int n)
 {
       ......
 } 

         可以使用以上任意一种函数原型和函数定义。

*/

#include<stdio.h>

int main(void)

{
         int zippo[4][2] = { { 2, 4 }, { 6, 8 },{ 1, 3 }, { 5, 7 } };

         printf("  zippo = %p, zippo + 1 = %p\n", zippo,zippo + 1);
         printf("zippo[0] = %p, zippo[0] +1 = %p\n", zippo[0], zippo[0] + 1);
         printf("zipp0[0][0] = %d\n",zippo[0][0]);
         printf(" *zippo[0] = %d\n",*zippo[0]);
         printf(" **zippo = %d\n",**zippo);
         printf("    zippo[2][1] = %d\n", zippo[2][1]);
         printf("*(*(zippo + 2) + 1) =%d\n", *(*(zippo + 2) + 1));

         return 0;
}

/*

         二维数组zippo的地址和一维数组zippo[0]的地址相同。它们的地址都是各自数组首元素的地址,因而与&zippo[0][0]的值也相同。

         差别:zippo[0]指向一个4字节的数据对象。zippo[0]加1,其值加4。数组名zippo 是一个内含2个int类型值的数组的地址,所以zippo指向一个8字节的数据对象。因此,zippo加1,它所指向的地址加8字节。

         zippo[0]*zippo完全相同。对二维数组名解引用两次,得到储存在数组中的值。使用两个间接运算符(*)或者使用两对方括号([])都能获得该值,还可以使用一个*和一对[]这种方法来实现。

         注意:与 zippo[2][1]等价的指针表示法是*(*(zippo+2) + 1)

         zippo   二维数组首元素地址(每个元素都是内含两个int类型元素的以为数组)

         zippo + 2  二维数组的第三个元素(即一维数组)的地址。

        *(zippo + 2) 二维数组的第三个元素(即一维数组)的首元素(一个int类型的值)地址。

        *(zippo + 2) + 1 二维数组的第三个元素(即一维数组)的第二个元素(一个int类型的值)地址。

       *(*(zippo + 2) + 1) 二维数组的第三个一维数组的第2个int类型元素的值,即数组的第三行第二列的值(zippo[2][1])。

*/


猜你喜欢

转载自blog.csdn.net/qq_20440225/article/details/79846413