指针与引用

指针与引用:

1、指针和引用的区别(1)

区别:

(1)引用只是别名,指针是一个对象,引用不能修改绑定对象,指针可以修改指向的对象

(2)有const指针,但是没有const引用,因为引用绑定的对象本身不能修改

(3)指针可以有多级,但引用只能是一级(引用不是对象,所以不能声明引用的引用)

(4)指针的值可以为空,但是引用的值不能用NULL,引用在定义的时候必须初始化

(5)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。

(6)"sizeof引用"得到的是所绑定的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小;

(7)指针和引用的自增(++)运算意义不一样;

指针自加,比如 int a[2] = {0,10} ;int *pa =a;
pa++表示指针往后移动一个int的长度。指向下一个内存地址。及pa从指向a[0]变成指向a[1]
引用是值++;比如b是引用a[0]的,++表示a[0]的值++从0变为1;

(8)指针间接访问时需要解引用(*),引用则不需要(引用是别名)

2、悬空指针与野指针区别(1)

野指针(wild pointer)就是没有被初始化过的指针。

 

悬空指针是指针最初指向的内存已经被释放了的一种指针。

如果两个指针(p1和p2)指向同一块内存区域, 那么free(p1)后,p1和p2都成为悬空指针。如果进一步将p1设置为NULL, 那么p2还是悬空指针。诚然,使用*p1会导致非法内存访问,但是使用*p2却会出现无法预料的结果

 

 

如何避免使用野指针和悬空指针?

如何避免使用野指针? 好办! 养成在定义指针后且在使用之前完成初始化的习惯就好。

 

避免悬空指针:智能指针的本质是使用引用计数(reference counting)来延迟对指针的释放。

参考文章:野(wild)指针与悬空(dangling)指针
int main(int argc, char *argv[])
{
    int *p;
    return (*p & 0x7f); /* XXX: p is a wild pointer */
}


//悬空指针
#include <stdlib.h>
int main(int argc, char *argv[])
{
        int *p1 = (int *)malloc(sizeof (int));
        int *p2 = p1;        /* p2 and p1 are pointing to the same memory */
        free(p1);            /* p1 is       a dangling pointer, so is p2  */
        p1 = NULL;           /* p1 is not   a dangling pointer any more   */
        return (*p2 & 0x7f); /* p2 is still a dangling pointer            */
}

 

3、C++中*和&同时使用是什么意思?(1)

类似于void *& fun (int *& a)这样的函数。

 

指针的引用,指针也是一个变量,可以有引用,其实就是指针变量的别名,在函数里面对a的值进行改变,那么在调用函数时传入的参数的指针值也会改变

 

void * fun (int *a)

如果形参是指针,传入的其实是指针形参的拷贝,函数内可以修改指针所指对象的值,但是不能改变指针的值

4、指针常量与常量指针(1)

常量指针

常量指针(被指向的对象是常量)
定义:又叫常指针,可以理解为常量的指针,指向的是个常量
关键点:
1. 常量指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改;(没有限制通过别的方式修改)
2. 常量指针可以被赋值为变量的地址,之所以叫常量指针,是限制了通过这个指针修改变量的值;
3. 指针还可以指向别处,因为指针本身只是个变量,可以指向任意地址;

 

声明方式:

const int *p; 

int const *p;

指针常量
指针常量(指针本身是常量)
定义:
本质是一个常量,而用指针修饰它。指针常量的值是指针,这个值因为是常量,所以不能被赋值。
关键点:
1. 它是个常量!
2. 指针本身是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化;

5、引用作为函数参数以及返回值的好处(2)

对比值传递,引用作为函数参数以及返回值的好处

(1)在函数内部可以对此参数进行修改(传递实参的别名)

(2)提高函数调用和运行的效率(没有了传值和生成副本的时间和空间消耗)

 

采用值传递,通过“形参=实参”来对形参赋值达到传值的目的,生成一个实参的副本。函数内部对形参的修改,不会对实参有任何影响。

用引用作为返回值最大的好处就是不产生被返回值的副本。

需要遵守的规则
参考链接:https://blog.csdn.net/weibo1230123/article/details/82014538

6、简述数组与指针的区别?(3)

7、int (*s[10])(int) 表示的是什么?(3)

8、复杂声明
void * ( * (*fp1)(int))[10];
float (*(* fp2)(int,int,int))(int);
int (* ( * fp3)())[10]();
分别表示什么意思?(3)

9、下列代码可以编译过吗?

/**************代码1*********************/
char *strA()   
{
    char str[]="hello world";
    return str;
}
/****************代码2****************/
const char *strA()
{
    char *str="hello world";
    return str;
}
/***************代码3***************/
const char *strA() 
{
    static str[]="hello world";
    return str;
}

分辨字符串常量和初始化列表快速记法:

当它初始化一个字符数组时,它就是一个初始化列表;其他任何地方,它都是一个字符串常量

char str[]="hello world"——是分配一个局部数组。

char* str="hello world"——是分配一个指针变量。

 

char *c="hello world";

*c='t'//这将是错误的,字符串常量存在只读区,只读区的内容无法修改。

char c[]="hello world";

c[0]='t'//这是可以的,局部区的数据是可以修改的。

 

代码1:由于定义的str[]是一个char数组变量,在编译期间,很明显知道了str[]是在栈上分配内存地址,所以编译器就把字符串“hello world”认为是该内存地址的内容,由于跳出函数之后被释放了 

 

代码2:这是对代码1的修改。由于str是char型指针变量,需要将它指向一个内存地址,编译期间,由于“hello world”是一个字符串常量,需要在存放在只读区(用于存放常量和程序)。所以str指针就指向只读区,而只读取的内容是无法更改的(所以加了const)

 

代码3:是代码1的改进。这里static变量保证了函数退出后,变量的内存不被释放。

参考:https://www.cnblogs.com/yexuannan/p/3621262.html

 10、指针和地址的关系

int a[3];a[0]=1;a[1]=1;a[2]=2; 

int* p=a;           //p是a[0]的地址

int* q=&a[2];     //q是a[2]的地址

a[q-p];          //(q的地址值-p的地址值)/sizeof(int)。注意这里需要除以sizeof(int)

 

11、区分几种定义

const char *p; //*p是const,p可变
const (char *) p;//p是const,*p可变
char* const p; //p是const,*p可变
const char* const p; //p和*p都是const
char const * p;// *p是const,p可变            
(char*) const p;//p是const,*p可变
char* const p;// p是const,*p可变
 

char const * p;   p内存一,*内存二,const内存二是常量,char内存二是字符常量

const (char *) p; p内存一,(char*)内存二字符变量,const,内存一常量

“(char*)”: 整个修饰p,因为不是*,不会跳转到新的内存,所以返回值还是p,还是内存1

 

链接:奇技淫巧

 12、指针函数和函数指针

指针函数的本质是返回指针的函数。

 

函数指针的本质是指向函数的指针。

 

int (*p)[3]指向数组的指针(括号优先)
int (*(*def))[3]二级指针,指向一个一维数组的指针,数组的元素都是int类型。
int **def[3]def是一个数组,里面装的是一个指向指针的指针(下标优先于间接访问)
double*(*gh)[10]gh是一个指针,它指向一个一维数组,数组元素都是double*
int*((*b)[10])就跟"int* (*b)[10]"是一样的,b是一维数组的指针
参考链接一个关于指针的问题 int (**def)[3]的解析
Long (* fun)(int)函数指针
double(*f[10])()数组,数组有10个元素,元素是指向函数的指针,函数没有参数且返回double类型
long *fun(int)一个函数声明,函数返回为long*类型的
int (*(*F)(int,int))(int);

F是一个函数的指针,指向的函数的类型是两个int参数,并且返回指针的函数,返回的函数指针指向有一个int参数且返回int的函数。

第一步:(*F)(int,int)

 

int (*a[10])(int)一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整型数

 

 13、迷途指针、悬空指针

迷途指针又称为悬浮指针,当你释放(delete)内存时,并没有将指向这块内存的指针置为空指针,那么这个指针将成为迷途指针。

 

说到释放内存(delete),我们知道c++里面已经有malloc/free,那为什么还需要new/delete?它们之间有什么不同?

 

malloc/free是c++/c里面的标准库函数,new/delete是c++的运算符。它们都可以用于动态申请和释放内存,但是对于非内部数据类型的对象而言,malloc/free是无法满足动态对象的要求的。对象在创建的时候自动运行构造函数,在消亡之前自动运行析构函数。由于它们是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加给malloc/free。因此c++语言需要一个完成内存分配和初始化工作的运算符new,以及清理与释放内存的运算符delete。
 

malloc函数的参数是接受需要分配的内存字节数,如果内存能够满足请求量,那么将会返回指向被分配块的起始地址


free函数释放的是指针指向的内存(释放的不是指针,而是指针指向的内存,指针依然存在


new会有两个事件发生:(1)内存被分配(2)为被分配的内存调用一个或多个构造函数构建对象。int* p=new int;


delete也会有两个事件发生:(1)为被释放的内存调用一个或多个析构函数(2)释放内存。


如果想要更深入地学习new和delete,可以参考这个书《深入探索c++对象模型》
 

//指针函数
#include<stdio.h>
int sum;
int *add(int a, int b)
{
        sum=a+b;
        return &sum;
}
int main()
{
        int *p;
        p=add(1,2);
        printf("add result is %d\n", *p);
        return 0;
}

//函数指针
#include<stdio.h>
int add(int x, int y)
{
        return (x+y);
}

int main()
{
        int (*p)(int, int);
        p=add;
        printf("add result is %d\n", p(200,300));
}

 

 

复合类型
 
 

声明语句:

一条声明语句由一个基本数据类型和紧随其后的一个声明符列表组成;每个声明符命名了一个变量并指定该变量为与基本数据类型有关的某种类型;

简单声明语句:声明符是变量名,变量类型是基本数据类型;eg:int a;

引用

1、作用:为对象起另外一个名字

2、int &d = a; //&d为声明符,定义引用类型,d为变量名,Int是基本数据类型

3、int & refVal;  //报错:引用必须被初始化; 

定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始对象一直绑定在一起。无法令引用重新绑定到另外一个对象,因此引用必须初始化。

引用即别名

1、引用并非对象,相反的,只是为一个已存在的对象起一个别名

2、因为引用并非对象,所以不能定义引用的引用

引用的定义

1、允许一条语句中定义多个引用,其中每个引用标识符必须以&开头

int &r = i, r2 = i2;    //r是一个引用,与i绑定在一起,r2是int

2、除了两种特例(初始化常量引用时允许任意表达式作为初始值(非常量对象、字面值),或者用基类引用绑定到一个派生类对象),其它所有引用的类型都要和绑定的对象严格匹配

3、引用只能绑定到对象上,不能与字面值或者某个表达式的计算结果绑定在一起

int & refVal4 = 10;  //错误:引用类型的初始值必须是一个对象

double dval = 3.14;

int &refVal5 = dval;  //错误:引用类型要和绑定对象严格匹配

指针

指针和引用的相同与不同:

相同处:都能实现对其它对象的间接访问

不同:

1、指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以指向几个不同的对象

2、指针无须在定义时赋初值。和其它内置类型意义,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。

 

int *d ; //*d为声明符,定义指针类型,d为变量名,Int是基本数据类型

 

允许一条语句中定义多个指针,其中每个指针标识符必须以*开头

 

不能定义指向引用的指针,因为引用不是对象,没有实际地址;

 

除了两种特例(const的指针,或者用基类指针指向一个派生类对象),其它所有指针的类型都要和它所指向的对象严格匹配

double dval;

double *pd = &dval;   //正确

int *pi = pd;  //错误:不匹配

指针值

指针的值(即地址)应该属下列四种状态之一:

1、指向一个对象

2、指向紧邻对象所占空间的下一个位置

3、空指针,意味着指针没有指向任何对象

4、无效指针,上述情况之外的其他值。

 

试图拷贝或访问无效指针将引发错误,编译器不负责检查此类错误

第2种、第3种形式指针有效,但是没有指向任何对象,试图访问此类指针行为不被允许

利用指针访问对象

解引用符*

解引用操作仅适用于确实指向了某个对象的有效指针

空指针

空指针不指向任何对象,在试图使用一个指针之前代码可以首先检查它是否为空

 

生成空指针的几个方法:

int *p1 = nullptr     //等价于int *p1 = 0;

int *p2 = 0;            //直接将P2初始化为字面常量0

//需要首先#include cstdlib

int *p3 = NULL;     //等价于int *p3 = 0;

1、nullptr是c++11引入的字面值,可以转换为任意其他的指针类型

2、也可以用字面值0

3、NULL是预处理变量,头文件cstdlib中定义,值为0;当用到一个预处理变量时,预处理器自动将它替换为实际的值,因此用NULL初始化指针和用0是一样的

!!!将int变量直接赋给指针是错误的,即使变量值恰好为0

int zero = 0;

int* p = zero;      //错误:不能直接把int变量赋给指针

!!!建议初始化所有指针,如果使用了未经初始化的指针,则该指针所占空间的当前内容被看到一个地址值,就很难区分到底是合法还是非法了。实在不清楚指针应该指向何处,把他初始化为nullptr或者0,这样程序就能检测并知道它没有指向任何具体的对象了

 

指针操作

1、如果指针的值是0,if取false

if(pi)              //若pi的值是0,取false,和采用算术值作为条件类似

2、两个指针存放的地址值相同有三种可能:

  • 它们都为空
  • 都指向同一对象
  • 都指向了同一对象的下一地址
void*指针

1、void*指针可用于存放任何对象的地址,但是对该地址中到底是一个什么类型的对象并不了解

2、因此不能直接操作void*指针所指对象,可以拿它跟别的指针比较、作为函数输入输出、或者赋给另外一个void*指针

 

理解符合类型的声明

同一条语句中,基本数据类型只有一个,但是声明符的形式可以不同,也就是:一条定义语句可能定义不同类型的变量

int i = 1024, *p = &i, &r = i;     //其中&,*是类型修饰符,是声明符的一部分,修饰的是变量名,而不是类型,所以对声明语句中的其它变量,并不起作用

指针和引用的两种写法:

1、把修饰符和变量标识符写在一起,强调变量具有符合的类型

2、修饰符和类型名写在一起,并且每条语句只定义一个变量,强调本次声明定义了一个复合类型 

int *p1, *p2;

int* p3;

 

指向指针的指针、指向指针的引用

int *p;

int *&r = p;   //r是一个对指针的引用

最简单的方法是从右向左阅读r的定义

const限定符

1、任何试图对const变量进行赋值的行为都将引发错误

2、const对象一旦创建了之后其值不再改变,所以const对象必须初始化。初始值可以是任何复杂的表达式

const int bufSize = 512;

bufSize = 512;                 //错误:试图向const写值

 

const int i = get_size();    //正确:运行时初始化

const int j = 42;                //正确:编译时初始化

const int k;                       //错误:k是一个未经初始化的常量

 

初始化和const

 

int i = 42;

const int ci = i;   //正确:i的值被拷贝给了ci

int j = ci;             //正确:ci的值被拷贝给了j

const对象的主要限制是只能在const对象上执行不改变其内容的操作;

可以进行:const int 与Int的算术运算,初始化

如果利用一个对象初始化另一个对象,是不是const都无关紧要(const属性仅仅在执行改变ci的操作才发挥作用)

在默认情况下,const对象仅在文件内有效

1、当多个文件同时出现了同名的const变量时,其实相当于在不同文件定义了独立的变量

2、如果想在多个文件之间共享const对象,必须在定义的变量之前添加extern关键字

//file_1.cc

extern const int bufSize = fcn();

//file_1.h

extern const int bufSize;

 

const的引用

1、对常量的引用不能用来修改绑定的常量的对象

2、不能让一个非常量引用指向一个常量对象

const int ci = 1024;

const int &ri = ci;         //错误:r1是对常量的引用

int &r2 = ci;                  //错误:试图让一个非常量引用指向一个常量对象,若该初始化合法,则可以通过r2来改变它引用对象的值,显然不正确

 

 

初始化和对const的引用

1、初始化常量引用时允许任意表达式作为初始值(非常量对象、字面值),只要该表达式的结果能转换成引用的类型,如double转int即可。    程序中,ri绑定的是一个临时量对象(编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未知名对象)

double dval = 3.14;

cont int &ri = dval;

 

编译器进行的工作:

const int temp = dval;    //由双精度浮点型生成一个临时的整型常量

const int &ri = temp;      //由ri绑定这个临时量

当ri不是常量时,绑定的是一个临时量,还是不能通过ri改变dval的值,无意义,C++也把这种行为归为非法行为。

 

这就是为啥

可以用常量的引用绑定一个非常量(其实绑定的是一个临时量)

不能用非常量的引用绑定一个常量(无意义,定为非法)

指针和const(与引用类似)

1、指向常量的指针不能用于改变其所指的对象

2、存放常量对象的地址,只能使用指向常量的指针

3、允许另一个指向常量的指针指向一个非常量对象

(使用常量的指针仅仅要求不能通过该指针改变对象的值,并没有规定那个对象的值不能通过其他途径改变)

double dval = 3.14;                 //一个双精度浮点型,其值可以改变

const double *cptr = &dval;    //正确:但是不能通过cptr改变dval的值

 

常量指针与指向常量的指针
1、常量指针必须初始化,而且一旦初始化完成,它的值就不再改变

C和指针

指针变量的内容
变量的值就是该变量的内存位置所存储的数值,指针也是,只不过存储的是指向对象的地址
间接访问操作符
通过*单目操作符,实现间接访问或者解引用指针
未初始化与非法的指针

int *a;

*a = 12;

声明一个指向常量的指针,指针变量就不会被分配存储空间;  

如果没有初始化,指针变量和其它变量并无区别,如果变量是静态的,被初始化为0;如果变量是自动的,根本不被初始化;

 

执行赋值操作,

运气好,a的初始值是一个非法地址,报错,“段违例”或“内存错误”;

严重的,指针可能包含一个合法地址,位于那个位置的值被修改

 

解决方法是指针必须初始化后,才能使用。

指针表达式(C与指针p100)

char ch = 'a';

char *cp = &ch;

表达式右值左值
ch'a'   ch的地址
&chch的地址非法(并未标志任何机器内存的特定位置,所以不是一个合法的左值)
cpcp的值cp的内存位置
&cpcp的地址非法
*cpch的值ch的地址
*cp+1

(*的优先级高于+)

取得这个值的拷贝并加1,最终结果为字符‘b‘;

表达式的最终结果的存储位置并未清晰定义,不是一个合法的左值
*(cp+1)cp之后的内存位置的值cp之后的内存位置
++cp

增值后的指针的一个拷贝

(前缀++先增加cp的值再返回cp的值的一份拷贝)

非法
cp++

cp原来的值的一份拷贝

(后缀++先返回cp的值的一份拷贝再增加cp的值)

非法
*++cp

ch后的内存位置的值

(间接访问操作符作用于增值后的指针的拷贝上)

地址
*cp++

ch的值

1、产生cp的一份拷贝

2、增加cp的值

3、在cp的拷贝上执行间接访问操作

地址
++*cp

1、间接访问

2、cp所指向位置增值

3、增值后的值的一份拷贝

 
(*cp)++

ch增值前的原先值

1、间接访问

2、返回ch的值

3、增加ch的值

 
++*++cp

1、++cp,cp增加后拷贝

2、*,对拷贝值间接访问,访问ch后面的那个内存位置

3、++,增加后面那个内存位置的值

 
++*cp++

1、cp++,cp拷贝后增加

2、*,对拷贝值间接访问,访问原cp指向的位置的值

3、++,增加原cp指向位置的值

 

++优先于*,*优先于+

前缀++先增加再返回拷贝,后缀++先返回拷贝再增加

数组

数组名
 
 

int a;

int b[5];

数组名的值是一个指针常量,也就是指针第一个元素的地址;b:指向int的常量指针

只有当数组名在表达式中使用时,编译器才会为它产生一个指针常量

 

在以下两种情况中,数组名不能用指针常量表示:

1、数组名作为sizeof操作符(返回的是整个数组的长度,而不是指向数组的指针的长度)

2、&操作数(产生的是一个指向数组的指针,而不是指向常量指针的指针)

 

int a[10];

int b[10];

int *c;

 

c = &a[0];    //&a[0]是一个指向数组第一个元素的指针,正是数组名本身的值

c = a;           //等同上句,被赋值的是一个指针的拷贝,而不是整个数组

 

b = a;           //非法,不能用赋值符把一个数组的所有元素复制到另外一个数组,需要用循环,每次复制一个元素

 

a = c;           //非法,a是一个常量指针,不能被修改

 

下标引用

除了优先级之外,下标引用和间接访问完全相同。

int array[10];

int *ap = array + 2;

*aparray[2]
ap[0]

下标引用同间接引用,因此等价:

*(ap+0),所以还是array[2]

ap+6&array[8]
*ap+6array[2]+6
*(ap+6)array[8]
ap[6]*(ap+6):array[8]
&ap 
ap[-1]array[1]

 

指针与数组

指针和数组并不是相等的

int a[5];

int *b;

声明一个数组时,编译器根据声明所指定的元素数量为数组保存内存空间,然后再创建数组名,它的值是一个常量,指向这段空间的起始位置;

声明一个指针变量时,编译器只为指针本身保留内存空间,它不为任何整型值分配内存空间。而且,指针变量并未初始化为指向任何现有内存空间,如果它是一个内存变量,甚至不会被初始化。

 

b++可以通过编译,a++不行,因为a的值是一个常量

作为函数参数的数组名

通过传值方式传递的,传递给函数的是一份指针的拷贝,可以修改它所指向的内容,但是不会修改指针实参本身

void strcp(char* buffer, char const *string) {

        while( (*buffer++ = *string++) != '0' )    //buffer++对buffer的增值,不会影响传递的指针实参

}

 

声明数组参数

int strlen(char *string);

int strlen(char string[]);

两种相等,调用函数时实际上传递的是指针的一个拷贝

 

!!!数组形参可以与任何长度的数组匹配,函数原型的一维数组形参无须写明它的元素数目,因为函数并不为数组参数分配内存空间,形参只是一个指针,指向的是已经再其他地方分配好内存的空间

 

数组初始化

取决于存储类型:

1、存储于静态内存的数组只初始化一次,也就是在程序执行之前

2、自动变量:自动变量位于运行时堆栈中,执行流每次进入它们所在的代码中,这类变量每次所处的内存位置可能不同,因此,自动变量在缺省情况下是未初始化的。  如果在自动变量的声明中给出了初始值,每当执行流进入自动变量声明所在的作用域时,变量就被一条隐式的赋值语句初始化。    如果每次都对数组重新初始化不值得,就要把数组声明为static


 

char message1[] = "Hello";     //前一个初始化字符数组的元素

char *message2 = "Hello";      //后一个是字符串常量,初始化一个指针变量

分辨字符串常量和初始化列表快速记法:

当它初始化一个字符数组时,它就是一个初始化列表;其他任何地方,它都是一个字符串常量

多维数组

数组元素的存储顺序:按照最右边下标率先变化的原则,行主序

 

下标(同间接访问)

int matrix[3][10];一个一维数组,包含3个元素,每个元素是包含10个整型元素的数组
matrix指向包含10个整型元素的数组的指针
matrix+1指向包含10个整型元素的数组的指针,指向另一行
*(matrix+1)包含10个整型元素的数组,数组名的值是个常量指针,指向第2行数组的第一个元素
*(matrix+1)+5指针,指向第二行数组第6个元素

 

指向数组的指针

int vector[10], *vp = vector;           //正确:vector和vp都是指向整型的指针

int matrix[3][10], *mp = matrix;      //错误:matrix是一个指向整型数组的指针

 

int (*p)[10];               //声明一个指向整型数组的指针,下标的优先级高于间接访问,所以加括号

//首先执行间接访问,所以p是一个指针,接着执行下标引用,所以p指向某种类型的数组

 

int (*p)[10] = matrix;     //p指向matrix第一行

 

作为函数参数的多维数组

1、与一维数组区别,一维数组形参不用知道维数,但是多维数组需要,以便确定调整因子,为函数形参的下标表达式进行求值

 

int vector[10];

 

void func1(int *vec);

void func1(int vec[]);

//作用于vec上面的指针运算把整型的长度作为调整因子

 

int matrix[3][10];

void func2(int (*mat)[10]);

void func2(int mat[][10]);

//mat的第一个下标根据包含10个元素的整型数组的长度进行调整,接着第二个下标根据整型的长度进行调整

 

多维数组初始化

数组元素的存储顺序是根据最右边下标率先变化的原则确定的

int matrix[2][3] = {100,101,102,103,104,105};

 

int matrix1[3][3] = {

     {00,01,02},

     {10,11,12},

     {20,21,22}

};

 

//只有第一维可以根据初始化列表缺省地提供

int matrix1[][3] = {

     {00,01,02},

     {10,11},

     {20,21,22}

};

 

指针数组
int *api[10];    //下标优先级高于间接访问,首先执行下标引用,所以是一个数组,取得数组元素之后进行间接访问,所以元素是指向整型地指针

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值