指针是什么?
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
指针是用来存放地址的,地址是唯一标示一块地址空间的。
指针的大小在32位平台是4个字节,在64位平台是8个字节。
指针和指针类型
这里我们在讨论一下:指针的类型 我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢? 准确的说:有的。
指针的定义方式是: type + * 。其实: char* 类型的指针是为了存放 char 类型变量的地址。 short* 类型的指针是为了存放 short 类型变量的地址。 int* 类型的指针是为了存放 int 类型变量的地址。
指针±整数
指针的类型决定了指针向前或者向后走一步有多大(距离)。
指针的解引用
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。 比如: char* 的指针解引用就 只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
指针和数组
数组名表示的是数组首元素的地址。
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组。
如下:
int main() {
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++) {
printf("%d ", *(p + i));
}
return 0;
}
指针数组
指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。
那指针数组是怎样的?
int* arr[5];//是什么?
arr是一个数组,有五个元素,每个元素是一个整形指针。
字符指针
在指针的类型中我们知道有一种指针类型为字符指针 char* ;
一般使用:
int main() {
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
还有一种使用方式如下:
int main() {
char* pstr = "hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?
printf("%s\n", pstr);
return 0;
}
代码 char* pstr = “hello bit.”;特别容易让同学以为是把字符串 hello bit 放到字符指针 pstr 里了,但是本质是把字符串 hello bit. 首字符的地址放到了pstr中。上面代码的意思是把一个常量字符串的首字符 h 的地址存放到指针变量 pstr 中。
数组指针
数组指针是指针?还是数组?
答案是:指针。
我们已经熟悉: 整形指针: int * pint;能够指向整形数据的指针。 浮点型指针: float * pf;能够指向浮点型数 据的指针。
那数组指针应该是:能够指向数组的指针。
下面代码哪个是数组指针?
int *p1[10];
int (*p2)[10];
//p1, p2分别是什么
int (*p)[10];
//解释:p先和 * 结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于 * 号的,所以必须加上()来保证p先和 * 结合。
&数组名VS数组名
#include <stdio.h>
int main() {
int arr[10] = {0};
printf("%p\n", arr);
printf("%p\n", &arr);
return 0;
}
可见数组名和&数组名打印的地址是一样的。
难道两个是一样的吗?
我们再看一段代码:
#include <stdio.h>
int main() {
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
printf("arr+1 = %p\n", arr+1);
printf("&arr+1= %p\n", &arr+1);
return 0;
}
根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。
实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。
函数指针
首先看一段代码:
#include <stdio.h>
void test() {
printf("hehe\n");
}
int main() {
printf("%p\n", test);
printf("%p\n", &test);
return 0;
}
输出的是两个地址,这两个地址是 test 函数的地址。 那我们的函数的地址要想保存起来,怎么保存? 下面我们看代码:
void test() {
printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();
首先,能给存储地址,就要求pfun1或者pfun2是指针,那哪个是指针? 答案是:
pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。
回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
#include<stdio.h>
typedef int(*Cmp)(int a, int b);
void swap(int *a, int *b) {
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void bubbleSort(int *a, int num, Cmp cmp) {
int i, j;
for (i = 0; i < num; ++i) {
for (j = 0; j < num - i - 1; ++j) {
if (!cmp(a[j], a[j + 1])) {
swap(&a[j], &a[j + 1]);
}
}
}
}
int Less(int a, int b) {
return a < b ? 1 : 0;
}
int Greater(int a, int b) {
return a > b ? 1 : 0;
}
int main() {
int a[4] = { 9, 5, 2, 7 };
bubbleSort(a, 4, Greater);
int i;
for (i = 0; i < 4; ++i) {
printf("%d ", a[i]);
}
putchar('\n');
system("pause");
return 0;
}
以上代码是冒泡排序,而是通过回调函数的方式,来确定排序规则。