数组指针和指针数组的区别

半世苍凉 提交于 2020-02-15 23:00:25

指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针

数组指针:a pointer to an array,即指向数组的指针

int* a[4]     指针数组     

                 表示:数组a中的元素都为int型指针    

                 元素表示:*a[i]   *(a[i])是一样的,因为[]优先级高于*

int (*a)[4]   数组指针     

                 表示:指向数组a的指针

                 元素表示:(*a)[i]  

注意:在实际应用中,对于指针数组,我们经常这样使用:
typedef int* pInt;
pInt a[4];
这跟上面指针数组定义所表达的意思是一样的,只不过采取了类型变换。

代码演示如下:
#include <iostream>
using namespace std;
int main()
{
int c[4]={1,2,3,4};
int *a[4]; //指针数组
int (*b)[4]; //数组指针
b=&c;
//将数组c中元素赋给数组a
for(int i=0;i<4;i++)
{
a[i]=&c[i];
}
//输出看下结果
cout<<*a[1]<<endl; //输出2就对
cout<<(*b)[2]<<endl; //输出3就对
return 0;
}
注意:定义了数组指针,该指针指向这个数组的首地址,必须给指针指定一个地址,容易犯的错得就是,不给b地址,直接用(*b)[i]=c[i]给数组b中元素赋值,这时数组指针不知道指向哪里,调试时可能没错,但运行时肯定出现问题,使用指针时要注意这个问题。但为什么a就不用给他地址呢,a的元素是指针,实际上for循环内已经给数组a中元素指定地址了。但若在for循环内写*a[i]=c[i],这同样会出问题。总之一句话,定义了指针一定要知道指针指向哪里,不然要悲剧。

测试:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
#include <string.h>


void SaveSplitRecord(char *result)
{
    FILE *fileSplit;
    if ((fileSplit = fopen("C:/Users/ranjiewen/Desktop/split.txt", "rb+")) == NULL)  //如果文件读写错误,返回null
    {
        if ((fileSplit = fopen("C:/Users/ranjiewen/Desktop/split.txt", "wb")) == NULL)
            return;
    }

    fseek(fileSplit, 0L, SEEK_END);
    //fwrite(result, 1, sizeof(result), fileSplit);
    int a = sizeof(result);

    fwrite(result,strlen(result), 1,fileSplit);
    fclose(fileSplit);

    return;
}

int main()
{
    //SaveSplitRecord("abcdefgdff!");
    int a[3][4] = { 0, 1, 2, 3,4,5,6,7,8,9,10,11};
    int *b[3];//指针数组
    //初始化
    for (int i = 0; i < 3;i++)
    {
        b[i] = a[i];
    }
    //取数组的元素  *(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]
    cout << "b[i][j]输出:" << endl;
    for (int i = 0; i < 3;i++)
    {
        for (int j = 0; j < 4;j++)
        {
            cout << b[i][j]<<" ";
        }
        cout << endl;
    }
    cout << "*(b[i]+j)"<<endl;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            cout << *(b[i]+j)<<" ";
        }
        cout << endl;
    }

    cout << "---------------数组指针-----------------" << endl;
    int   (*p)[4]; //每行有四个元素
    //初始化
    p = a;         // p=a[0]; p=&a[0][0];
    cout << p << endl;
    for (int i = 0; i < 3;i++)
    {
        cout << p[i]<<" ";
    }
    cout << endl;
    for (int i = 0; i < 3; i++)
    {
        cout << *p[i] << " ";  //输出第一列
    }
    cout << "-----------------------------" << endl;
    for (int i = 0; i < 3; i++)
    {
        cout << *p[i] << " ";  //输出一行
        cout << *(p[i]+1) << " ";  
        cout << *(p[i]+2) << " "; 
        cout << *(p[i]+3) << " "; 
    }

    cout << endl<<endl;

    p = p + 1; //移动一行距离
    for (int i = 0; i < 3; i++)
    {
        cout << p[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < 3; i++)
    {
        cout << *p[i] << " ";
    }
    cout << endl;

    return 0;
}

 

指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针

函数指针是指向函数的指针变量,即本质是一个指针变量

 

  1. int (*f)(int x); /*声明一个函数指针 */  
  2. f=func; /*将func函数的首地址赋给指针f */  

指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:
        类型说明符 (*函数名)(参数)
例如:
        void (*fptr)();
把函数的地址赋值给函数指针,可以采用下面两种形式:        

  1. (1)fptr = &Function;  
  2. (2)fptr = Function;  

取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址。

如果是函数调用,还必须包含一个圆括号括起来的参数表。
通过指针调用函数,可以采用如下两种方式:

  1. (1)x=(*fptr)();  
  2. (2)x=fptr();  

第二种格式看上去和函数调用无异,但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。下面举一个例子:

  1. void (*funcp)();  
  2. void FileFunc(),EditFunc();  
  3.   
  4. main()  
  5. {  
  6.   funcp = FileFunc;  
  7.   (*funcp)();  
  8.   funcp = EditFunc;  
  9.   (*funcp)();  
  10. }  
  11.   
  12. void FileFunc()  
  13. {  
  14.   printf(FileFunc\n);  
  15. }  
  16.   
  17. void EditFunc()  
  18. {  
  19.   printf(EditFunc\n);  
  20. }  

程序输出为:
   FileFunc
   EditFunc

 

二、指针的指针
    char ** cp;
指针的指针需要用到指针的地址。

  1. char c='A';  
  2. char *p=&c;  
  3. char **cp=&p;  

通过指针的指针,不仅可以访问它指向的指针,还可以访问它指向的指针所指向的数据。例如:

  1. char *p1=*cp;//访问它指向的指针  
  2. char c1=**cp;//访问它指向的指针所指向的数据  

利用指针的指针可以允许被调用函数修改局部指针变量和处理指针数组

  1. void FindCredit(int **);  
  2.   
  3. main()  
  4. {  
  5.    int vals[]={7,6,5,-4,3,2,1,0};  
  6.    int *fp=vals;  
  7.    FindCredit(&fp);  
  8.    printf(%d\n,*fp);   //输出-4
  9. }  
  10.   
  11. void FindCredit(int ** fpp)  
  12. {  
  13.    while(**fpp!=0)  
  14.      if(**fpp<0) break;  
  15.      else (*fpp)++;  
  16. }  

   首先用一个数组的地址初始化指针fp,然后把该指针的地址作为实参传递给函数FindCredit()。FindCredit()函数通过表达式**fpp间接地得到数组中的数据。为遍历数组以找到一个负值,FindCredit()函数进行自增运算的对象是调用者的指向数组的指针,而不是它自己的指向调用者指针的指针。语句(*fpp)++就是对形参指针指向的指针进行自增运算的。但是因为*运算符高于++运算符,所以圆括号在这里是必须的,如果没有圆括号,那么++运算符将作用于二重指针fpp上。

三、指向指针数组的指针
   指针的指针另一用法旧处理指针数组。有些程序员喜欢用指针数组来代替多维数组,一个常见的用法就是处理字符串。

  1. char *Names[] = {Bill, Sam, Jim, Paul, Charles, 0};  
  2.   
  3. main()  
  4. {  
  5.    char **nm=Names;  
  6.    while(*nm!=0) printf(%s\n,*nm++);  
  7. }  

   先用字符型指针数组Names的地址来初始化指针nm。每次printf()的调用都首先传递指针nm指向的字符型指针,然后对nm进行自增运算使其指向数组的下一个元素(还是指针)。注意完成上述认为的语法为*nm++,它首先取得指针指向的内容,然后使指针自增。
    注意数组中的最后一个元素被初始化为0,while循环以次来判断是否到了数组末尾。具有零值的指针常常被用做循环数组的终止符。程序员称零值指针为空指针(NULL)。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!