目录

  • 前言
  • 1. 字符指针
  • 2. 数组指针
    • 2.1 数组指针的定义
    • 2.2 & 数组名 VS 数组名
    • 2.3 数组指针的应用
  • 3. 数组传参和指针传参
    • 3.1 一维数组传参
    • 3.2 二维数组传参
    • 3.3 一级指针传参
    • 3.4 二级指针传参
  • 4. 函数指针
  • 5. 函数指针数组
  • 6. 指向函数指针数组的指针
  • 7. 回调函数

前言

本篇为指针的进阶,如果初阶指针还不太明白的伙伴们请戳:初阶指针。
指针的基本概念:

  1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
  2. 指针变量的大小是4/8个字节(根据32/64位平台)。
  3. 指针是有类型的,指针的类型决定了指针±整数的的步长,指针解引用操作时可以访问的范围。
  4. 指针的简单运算。

1. 字符指针

在指针的类型中我们知道有一种指针类型为字符指针 char* ;

int main()
{char ch = 'a';char* pc = &ch;*pc = 'b';return 0;
}

还可以写成下面这种形式:

int main()
{char* pc = "abcd";//是指针里存了一个字符串吗printf("%s\n", pc);return 0;
}

并不是,其实是把字符串的首元素地址a存放到指针pc里,%s只要给出字符串的起始地址,一直打印到\0之前。

因为此字符串为常量字符串,不能被修改,放在未被修饰的指针变量不安全,此时在前面加上const修饰,使其无法被修改,这样就很好的保护了字符串。
const char* pc = "abcd";

一道面试题:

int main()
{char* p1 = "abcd";char* p2 = "abcd";char arr1[] = "abcd";char arr2[] = "abcd";if (p1 == p2)puts("p1 == p2");elseputs("p1 != p2");if (arr1 == arr2)puts("arr1 == arr2");elseputs("arr1 != arr2");return 0;
}
//输出的结果是什么?

那么这两种形式的区别在哪?画图分析:


2. 数组指针

在探究数组指针前,看回顾一下什么是指针数组:

指针数组 - 是数组。是用来存放指针变量的数组。

int arr[10];//整形数组
char brr[10];//字符数组
...
int* crr[10];//整形指针数组 - 存放整形指针的数组
char* drr[10];//字符指针数组

指针数组的作用:

int main()
{int arr[] = { 1,2,3 };int brr[] = { 2,3,4 };int crr[] = { 3,4,5 };//定义指针数组int* prr[3] = { arr, brr, crr };//数组名相当于首元素地址//把三个数组首元素放在prr里//是地址,因此prr的类型为整形指针类型return 0;
}

这种写法,其实也就模拟写成了一个二维数组,这该怎么理解?

那段代码所对应的意义,知道了该指针数组的布局,那么访问并打印prr数组里的内容几乎和二维数组无差:

int main()
{int arr[] = { 1,2,3 };int brr[] = { 2,3,4 };int crr[] = { 3,4,5 };int* prr[3] = { arr, brr, crr };//三个元素,对应下标0 1 2//找到对应的首元素地址for (int i = 0; i < 3; ++i){//再用一个下标向后偏移分别找到该数组里的每个元素for (int j = 0; j < 3; ++j){//prr[i][j] == *(prr[i] + j) == *(*(prr+i)+j)printf("%d ", *(prr[i] + j));}printf("\n");}return 0;
}

用一个指针数组巧妙地把三个一维数组结合在一起,好像一个二维数组,这是指针数组的一个作用。

二维数组在内存中是连续存放的,这三个一维数组不一定是,所以说是模拟二维数组。


2.1 数组指针的定义

在了解了指针数组之后,接下来探究数组指针:

整形指针 - 指向整形的指针
字符指针 - 指向字符的指针

数组指针 - 是指针 - 指向数组的指针

下面两条语句分别是什么含义:

int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?

[ ]的优先级要高于星号的,所以必须加上()来保证p先和*结合。

2.2 & 数组名 VS 数组名

要弄清楚数组指针如何使用,就必须再次理解数组名和&数组名的含义:

数组名通常是代表首元素的地址,但是有两个意外

  1. sizeof(数组名)
    这里的arr是整个数组,计算的是数组的总大小。

必须是内部单独放一个数组名

  1. &数组名
    这里的数组名表示的依然是整个数组,&数组名取出的是整个元素的地址。(单位是字节)

具体有什么区别?

代码说明:

int main()
{int arr[5] = { 0 };//数组首元素地址放在int*的指针int* p1 = arr;//取出整个数组的地址放在数组指针p2里int (*p2)[5] = &arr;//这两个指针的区别://p1存放的是第一个整形元素的地址,指向第一个元素,不能代表整个数组。//而p2存放的是整个数组arr的地址,指向的是一个数组。return 0;
}

去掉名字就是它的类型:int* \ int (*)[5]。
后面的方括号必须要带数组的元素个数,否者会警告。


2.3 数组指针的应用

了解了数组指针的基本概念,紧接着就来探究数组指针的用法:

打印数组元素:

int main()
{int arr[5] = { 1,2,3,4,5 };int (*p)[5] = &arr;//存放整个数组的地址for (int i = 0; i < 5; ++i){printf("%d ", *(*p + i));///首先解引用p找到了数组arr首元素的地址//即*p == arr//地址+i在解引用向后偏移找到每个元素}return 0;
}

这种用法用起来很别扭,其实是非常不合理的写法。

正常的写法应该是:

int main()
{int arr[5] = { 1,2,3,4,5 };int* p = arr;for (int i = 0; i < 5; ++i){printf("%d ", *(p + i));//存放首元素地址p的指针//p+i找每个元素地址//解引用找到元素}return 0;
}

这种方法和第一种比起来清晰程度不言自明。

数组指针的作用并不体现在一维数组上,在二维或者多维数组才是数组指针的妙用。

接下来探究数组指针正确的用法。
函数打印二维数组:

//有两种写法:
//数组传参数组接收:int arr[3][4]//数组传参实际上传过来的是首元素地址
//这里形参写成指针的形式该怎么写?
void print(???, int r, int c)
{
}
int main()
{int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };print(arr, 3, 4);return 0;
}


既然二维数组数组名是一它第一行一维数组的地址,那么形参就要设置一个指向一维数组地址的指针:

(*pa)是指针,指向数组,数组有四个元素(*pa)[4],每个元素是int类型
int (*pa)[4]

void print(int (*pa)[4], int r, int c)
{//pa+i指向第i行for (int i = 0; i < r; ++i){//pa+i解引用得到当前行的首元素地址for (int j = 0; j < c; ++j){//首元素地址+j再解引用得到当前元素printf("%d ", *(*pa + i) + j));//printf("%d ", pa[i][j]);}printf("\n");}
}int main()
{int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };print(arr, 3, 4);return 0;
}

为什么数组指针+1跳过一个数组:

pa 的类型是一个数组指针:int (*)[4]
pa是指向一个数组,数组4个整形元素
因此pa+1跳过一个4个int元素的数组.

了解了指针数组和数组指针来回顾并看看下面代码的意思:

int arr[5];
//arr是整形数组
int *parr1[10];
//parr1是整形指针数组
int (*parr2)[10];
//parr2是整形数组指针
int (*parr3[10])[5];
//parr3是存放数组指针的数组

int main()
{int arr[] = { 1,2,3 };int brr[] = { 1,0,1 };int crr[] = { 1,2,3 };int (*parr[3])[3] = { &arr, &brr, &crr };for (int i = 0; i < 3; ++i){int (*pa)[3] = parr[i];//把parr数组的元素依次赋值给数组指针pafor (int j = 0; j < 3; ++j){//pa是第i个数组的地址//先解引用得到当前数组首元素地址//再利用j偏移解引用分别得到每个元素printf("%d ", (*pa)[j]);}printf("\n");}return 0;
}

3. 数组传参和指针传参

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

3.1 一维数组传参

void test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int *arr)//ok?
{}
void test2(int *arr[20])//ok?
{}
void test2(int **arr)//ok?
{}
int main()
{int arr[10] = {0};int *arr2[20] = {0};test(arr);test2(arr2);return 0;
}

上面的传参形式都是正确的。


3.2 二维数组传参

void test(int arr[3][5])//ok?1
{}
void test(int arr[][])//ok?2
{}
void test(int arr[][5])//ok?3
{}
void test(int *arr)//ok?4
{}
void test(int* arr[5])//ok?5
{}
void test(int (*arr)[5])//ok?6
{}
void test(int **arr)//ok?7
{}
int main()
{int arr[3][5] = {0};test(arr);return 0;
}

2:error,原因:二维数组传参,函数形参的设计只能省略第一个[ ]的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
这样才方便运算。

4:error,原因:二维数组的数组名表示的是首元素地址,是第一行的地址。
第一行可以看成是包含5个整形元素的数组的地址,既然是数组的地址放在一级指针肯定是错的,应该用数组指针。

5:error,原因:arr先和[ ]结合,是数组,每个元素是int*,因此错误。

7:error,原因:二级指针是存放一级指针的,而数组的地址没法存放到二级指针。


3.3 一级指针传参

如果函数的形参部分是一级指针,那么调用时实参可以写成什么?

void print(int *p)
{}
int main()
{>   int a = 10;print(&a);>   int* pa = &a;print(pa);>   int arr[10];print(arr);return 0;
}

如果形参是一级指针,实参可以传整形的地址、整形指针和数组名(本质都是指针)。


3.4 二级指针传参

如果函数的形参部分是二级指针,那么调用时实参又可以写成什么?

void test(int** ptr)
{}
int main()
{int* p1;test(&p1);int* *p2 = &p1;test(p2);int* arr[10];test(arr)return 0;
}

形参是二级指针,实参可以:取地址一级指针、二级指针和指针数组。


4. 函数指针

数组指针是指向数组的指针,而函数指针就是指向函数的指针

&数组名取出的是数组的地址:

int main()
{int arr[5] = { 0 };int(*pa)[5] = &arr;//数组指针return 0;
}

那么&函数名取出的是函数的地址吗?

int Add(int x, int y)
{return x + y;
}
int main()
{//取出函数的地址printf("%p\n", &Add);return 0;
}

因此函数也是有地址的。

对于函数来说:&函数名和函数名都是函数的地址。
因此和printf("%p\n", Add);没有区别。

取出了函数的地址,要把它存起来,该怎么写?

其实是和数组指针非常类似:

(*pf)说明它是指针,(*pf)()这一对圆括号说明指向的是函数(函数调用操作符()),它指向的函数参数类型是int, int,返回类型是int,int (*pf)(int, int),指针pf存放的函数Add的地址。

int (*pf)(int, int) = &Add
int (*pf)(int x, int y) 参数名可以省略不写,只要参数类型即可。

既然有函数指针这个类型,那么就一定会有它的作用,接下来探究函数指针的作用:

把一个整形的地址取出来放在一个指针里,对指针解引用就可以找到并且修改它,对于函数指针来说,道理是一样的。

比如说利用指针来间接调用函数:

int Add(int x, int y)
{return x + y;
}
int main()
{//直接调用//int ret = Add(2, 3);//取地址放到指针pf里int (*pf)(int, int) = &Add;//这个&符可以省去//利用指针间接调用//对指针解引用,调用函数的同时传参int ret = (*pf)(2, 3);printf("%d\n", ret);return 0;
}

注:这种写法也是对的int ret = pf(2, 3);,可以不写*号,完全等同于int ret = Add(2, 3);这也就解释了为什么可以省略不写星号,上面带星号是为了更方便理解。
但是如果写上面那种形式就必须要带括号,否则就不是函数指针了

通过上面代码的理解,也许会觉得函数指针有点多此一举,反正都一样,通过指针调用还把代码搞复杂了,其实函数指针在这个环境下是比较复杂。

但在其他环境里函数指针还是非常有作用的,之后会介绍它的其它妙用。

先来看看两段有趣的代码:

//代码1
( *( void (*)() )0 )();//代码2
void ( *signal(int , void(*)(int) ) )(int);

第一个:

第二个:

虽然解释了它的含义,但还不是不太方便理解,函数参数是函数指针,返回类型也是函数指针,有些绕。

这时可以使用typedef来把该函数声明进行优化:

typedef unsigned int u_int;
//其实就是把unsigned int重命名为u_int//把函数指针优化
void(*)(int)
//把void (*)(int)类型重命名为pf_t

下面改造该代码:

typedef void (*pf_t)(int);
int main()
{void (* signal(int, void (*)(int) ) )(int);pf_t signal(int, pf_t);return 0;
}

这里来介绍一下函数指针的作用。

写一个简易的计算器,这个计算机包含加法和减法(乘法除法原理于与之相同,明白它的含义就好,不再实现):

//选1加法
//选2减法
//选0退出
int Sub(int x, int y)
{return x - y;
}
int Add(int x, int y)
{return x + y;
}
void menu()
{puts("*******************");puts("*****  1. Add  ****");puts("*****  2. Sub  ****");puts("*****  0. exit ****");puts("*******************");
}
int main()
{int input = 0;do{menu();printf("请输入功能:");there:scanf("%d", &input);int x = 0;int y = 0;switch (input){case 1:printf("请输入两个操作数:");scanf("%d %d", &x, &y);printf("%d\n", Add(x, y));break;case 2:printf("请输入两个操作数:");scanf("%d %d", &x, &y);printf("%d\n", Sub(x, y));break;case 0:printf("Exit calcu!\n");break;default:printf("错误!请重新输入:\n");goto there;break;}} while (input);return 0;
}

测试结果:

虽然运行结果没问题,但是不难发现代码的实现有些冗余,如果加上了乘法除法的代码的重复部分会更多。

这时就体现出了函数指针的巧妙:

封装一个函数calc来负责加减计算,因为函数名就是函数地址,可以把实现加减的函数地址作为calc的参数,选择1传入Add函数的地址,选择2传入Sub的地址,再利用函数指针来找到并调用当前函数。

void menu()
{puts("********************");puts("*****  1. Add  *****");puts("*****  2. Sub  *****");puts("*****  0. exit *****");puts("********************");
}
int Sub(int x, int y)
{return x - y;
}
int Add(int x, int y)
{return x + y;
}
//计算
//形参要设置函数指针
void calc(int (*pf)(int, int))
{int x = 0;int y = 0;printf("请输入两个操作数:");scanf("%d %d", &x, &y);printf("%d\n", pf(x, y));
}
int main()
{int input = 0;do{menu();printf("请输入功能:");there:scanf("%d", &input);int x = 0;int y = 0;switch (input){case 1:calc(Add);break;case 2:calc(Sub);break;case 0:printf("Exit calcu!\n");break;default:printf("错误!请重新输入:\n");goto there;break;}} while (input);return 0;
}

这里就巧妙地使用了函数指针来实现相对于简洁的代码,如果没有函数指针的概念,固然是没办法写成这种形式。

这种形式也叫做回调函数,通过函数指针,在适当的时候回头调用它所指向的函数。


5. 函数指针数组

把函数指针放在数组中就是函数指针数组

上面的两个函数Add和Sub,因为函数名就是函数的地址,把这两个函数放进数组里,数组的元素就是函数指针,而数组就叫做函数指针数组:

不妨来推导一下它的类型该怎么写,其实和函数指针比较类似:
int (*pf)(int, int) = Add; - 这是函数指针。
实际上把pf换成数组的形式,就是函数指针数组:
int (*arr[2])(int, int) = {Add, Sub};(元素个数可以省略)。
arr先和[ ]结合,是数组,把数组名arr和[ ]拿开,就是它的类型:函数指针,它的每个元素是函数指针。

int Sub(int x, int y)
{return x - y;
}
int Add(int x, int y)
{return x + y;
}
int main()
{//函数指针数组int (*arr[2])(int, int) = {Add, Sub};return 0
}

访问这个数组:

int Sub(int x, int y)
{return x - y;
}
int Add(int x, int y)
{return x + y;
}
int main()
{int (*arr[2])(int, int) = { Add,Sub };for (int i = 0; i < 2; ++i){int ret = arr[i](8, 4);printf("%d\n", ret);}return 0;
}


既然有函数指针数组这种形式,也就一定会有它的作用,利用这个数组,再把上面的计算器进行优化。

不仅仅想要实现加减乘除,还想要实现x & y、x | y、x ^ y…等等
如果要增加的多的功能,那么对应的case语句也必然也会增加,整体的代码就不容易阅读了,那可以用什么办法来简化代码?

这时利用函数指针数组,可以很大程度上优化代码,让其变得十分简洁。
代码的实现:首先需要创建一个函数指针数组 - int (*arr[])(int, int) = { 0,Add,Sub };
在最前面放个0,把两个函数的下标向后面推了一位,因此就可以根据input输入的值来直接对应其下标
如果input = 0;直接退出计算器,再如果input>=1 && input <=2,用数组下标实现对应的·函数调用,否则重新输入,代码实现:

void menu()
{puts("********************");puts("*****  1. Add  *****");puts("*****  2. Sub  *****");puts("*****  0. exit *****");puts("********************");
}
int Sub(int x, int y)
{                                                                   return x - y;
}
int Add(int x, int y)
{return x + y;
}
int main()
{int (*pfArr[])(int, int) = { 0,Add,Sub };   int input = 0;int x = 0;int y = 0;do{menu();printf("请选择功能:");there:scanf("%d", &input);if (!input){puts("Exit calc!");}else if (input >= 1 && input <= 2){printf("请输入两个操作数:");scanf("%d %d", &x, &y);int ret = pfArr[input](x, y);printf("%d\n", ret);}else{puts("请重新输入!");goto there;}} while (input);return 0;
}

非常巧妙,利用函数指针数组大大简化了代码。

后面如果想增加一些功能,只需要实现要增加的函数功能,再数组里加上函数名,再把判断条件修改一下,调用起来非常方便且代码简洁。

6. 指向函数指针数组的指针

函数指针数组,也是数组,那么就会有它的地址,取出该数组的地址,就应该存放到指向【函数指针数组】的指针,那么该指针的形式该怎么写?

int (*pfArr[])(int, int) = { 0,Add,Sub };这是函数指针数组,根据这个形式来改:
首先它是个指针(*ppfArr),指向的是一个数组(*ppfArr)[ ],数组的每个元素是函数指针( *(*ppfArr)[ ] )(),函数的参数是int, int,返回值是int
int ( *(*ppfArr)[] )(int, int) = &pfArr;
这便是指向函数指针数组的指针。

int main()
{//这是函数指针数组int (*pfArr[])(int, int) = { 0,Add,Sub };//指向函数指针数组的指针int (*(*ppfArr)[3])(int, int) = &pfArr;return 0;
}

既然是指针,它也可以存放在一个数组里去,也就是【指向函数指针数组的指针】的数组,这也是个数组,既然是数组也可…


7. 回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

首先介绍qsort函数的用法。

qsort是C语言的一个库函数,使用快速排序的思想实现的一个排序函数,它可以排序任意数据。
qsort参数:void qsort( void *base, size_t num, size_t width, int (*cmp)(const void *e1, const void *e2 ) );
四个参数:
void* base - 需要排序的数据的起始位置
size_t num - 待排序数据的元素个数
size_t width - 待排序数据元素的大小(字节)
int (*cmp)(const void *e1, const void *e2 ) - 函数指针(比较函数),调用该指针指向的函数,参数e1和e2是要比较的两个元素的地址,因此该函数什么类型的数据都可以比较。


注意:第四个函数指针指向的函数其参数是void*的指针,void*的指针是无具体类型的指针,可以接收任意类型的地址,又因如此,所以void*的指针是无法进行解引用操作,也不能±整数的操作(因为并不知道传的是什么类型的地址,之能设置为void*类型),因此就需要强制类型转换为目标类型指针


该比较函数的返回值:

利用qsort来实现数组排序:

int cmp_int(const void* e1, const void* e2)
{return (*(int*)e1 - *(int*)e2);
}
int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(int), cmp_int);for (int i = 0; i < sz; ++i){printf("%d ", arr[i]);}return 0;
}


qsort排序结构体成员:

struct Stu
{char name[20];int age;
};
int cmp_stu_by_name(const void* e1, const void* e2)
{//利用strcmp来比较字符串return strcmp( ((struct Stu*)e1)->name, ((struct Stu*)e2)->name );
}
int cmp_stu_by_age(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int main()
{struct Stu s[] = { {"zhangsan", 15}, {"lisi",20}, {"wangwu",25} };int sz = sizeof(s) / sizeof(s[0]);//通过名字排序qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);//通过年龄排序qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);return 0;
}

名字排序

年龄排序:

在了解了qsort函数的使用,接下来基于冒泡排序的思想改造qsort函数:

void Swap(char* p1, char* p2, int width)
{for (int i = 0; i < width; ++i){char tmp = *p1;*p1 = *p2;*p2 = tmp;++p1;++p2;}
}
int cmp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
void bubble_sort(void* base, int num, int width, int(*cmp)(const void* e1, const void* e2))
{for (int i = 0; i < num - 1; ++i){int f = 1;for (int j = 0; j < num - i - 1; ++j){if (cmp( (char*)base + j * width, (char*)base + (j + 1) * width ) > 0){Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);f = 0;}}if (f == 1){break;}}
}
int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(int), cmp_int);for (int i = 0; i < sz; ++i){printf("%d ", arr[i]);}return 0;
}

运行结果:


以上便是对指针深入的探究,指针类型有很多一不小心就容易搞混,所以在学习指针时要认真且大量的反复观看一熟练掌握指针。

深入探究指针及指针类型相关推荐

  1. [C++] 指向常量的指针 VS 指针类型的常量

    指向常量的指针 VS 指针类型的常量 const 修饰指针时的位置不同,作用也不相同. 1. 指向常量的指针 不能通过指向常量的指针改变所指对象的值,但指针本身可以改变,可以指向另外的对象. 例: i ...

  2. 【C 语言】数组 ( 数组指针 | 数组指针定义 | 使用 数组类型* 定义数组指针 )

    文章目录 总结 一.使用 数组类型* 定义数组指针 二.完整代码示例 总结 typedef int(ArrayType)[3];ArrayType *p = NULL; 一.使用 数组类型* 定义数组 ...

  3. C语言指针转换为intptr_t类型

    C语言指针转换为intptr_t类型 1.前言 今天在看代码时,发现将之一个指针赋值给一个intptr_t类型的变量.由于之前没有见过intptr_t这样数据类型,凭感觉认为intptr_t是int类 ...

  4. Go_笔试题记录-指针与值类型实现接口的区别

    1.如果Add函数的调用代码为: func main() {var a Integer = 1var b Integer = 2var i interface{} = &asum := i.( ...

  5. c++ 表达式必须包含指向类的指针类型_C++:18const关键字(附常量指针、指针常量、常量指针常量)...

    一.const变量的一些基本特点 ①const修饰的变量不能被修改 const int a=10; a=20;//错误 ②因为const修饰的变量不能被修改,所以必须被初始化 int a=10; co ...

  6. C++之指针探究(六):二级指针和指针数组

    前文:C++之指针探究(五):数组指针和二维数组 使用指向指针的指针来指向指针数组,至少有以下两个优势:   ♠\spadesuit♠ 避免重复分配内存(下例中虽然我们进行了多个分类,但每本书名只占据 ...

  7. C++之指针探究(四):指针和二维数组

    前文:C++之指针探究(三):指针数组和数组指针 一. 二维数组 二维数组通常也被称为矩阵(matrix). 六种初始化方式:   (1) int a[3][4] = {1,2,3,4,5,6,7,8 ...

  8. C++之指针探究(三):指针数组和数组指针

    前文:C++之指针探究(二):一级指针和一维数组 一. 指针数组 或: 指针数组的本质是数组,数组中每一个成员是一个指针.定义形式如下:   char∗\ast∗ pArray[10]; 语法解析:p ...

  9. 对指针的详细认识(一)—— 指针概念+指针类型+野指针+指针运算+二级指针

    文章目录 指针是什么? 指针的定义 指针的大小 指针类型 指针有哪些类型? 指针类型有什么意义? 野指针 野指针的成因 如何避免野指针 指针运算 指针+-整数 指针-指针 指针的关系运算 二级指针 指 ...

最新文章

  1. SharePoint 2010 新体验5 - Office Web Applications
  2. IBM 推出 Bluemix :Swift 将支持服务器端开发
  3. 主从mysql能过滤指定dml吗_MyCat教程二:mysql主从复制实现 - HG-93
  4. 0502团队项目 SCRUM团队成立
  5. Visual Studio Code设置断点时出现Unverified breakpoint该咋办
  6. vscode终端进程已终止 - 问题采集
  7. [DFS] [BFS] poj1979 poj3009 poj3669
  8. c语言内循环外循环怎么使用,开高速, 用内循环还是外循环? 教你正确使用内外循环!...
  9. poj 3468 A Simple Problem with Integers 基础线段树
  10. 不为人知的网络编程(八):从数据传输层深度解密HTTP
  11. vue 微信公众号 前端开发
  12. Android 滑动放大,Android多点触控实现对图片放大缩小平移,惯性滑动等功能
  13. 场景法设计测试用例ATM机取款问题
  14. KEIL MDK平台 S3C2440 编译链接、烧写调试
  15. 匈牙利算法解决指派问题清晰流程
  16. 常用计算机系统包括,常用的保护计算机系统的方法有()。
  17. 自然场景文字检测方案总结
  18. kindeditor自定义添加网络视频插件,修改批量图片上传方式flash为h5
  19. 网站域名被劫持、网站dns被劫持 域名跳转到别的网站的解决方法
  20. 怎么用计算机算拔模斜度,拔模斜度怎么标注【带斜度CAD图形的标注方法详细步骤】...

热门文章

  1. 线程(线程基本概念、java实现多线程、使用多线程、线程的生命周期、线程同步、线程死锁)
  2. C++ 实现matlab中值滤波函数medfilt2
  3. Linux系统编程之进程退出,父进程等待子进程退出
  4. php redis消息订阅与发布_PHP实现redis订阅和发布(用于异步任务处理)
  5. 【产品】产品设计:印刷文件准备要求详解
  6. 基于AlexNet实现宠物小精灵(宝可梦)分类任务
  7. 数据库中存储大量图片设计
  8. root登录Linux图形界面
  9. Redis安装(Windows版本)
  10. 成都温江少年宫计算机培训班,温江建成13个乡村少年宫 农村孩子家门口开课