- #include
- int main()
- {
- int a = 0;
- //a是整型变量,占用四个字节的内存空间,在内存中开辟一块空间
- int* pa = &a;
- printf("%p", pa);
- //pa是一个指针变量,用来存放地址,这里是将a的四个字节的第一个字节的地址存放在ap变量中
- return 0;
- }
x86 - 32位
x64 - 64位


- int a = 5;
-
- 假设有以上a变量,那么我们可以将a的地址储存进以下指针变量中
-
- char* pc = &a;
-
- short* ps = &a;
-
- int* pi = &a;
-
- long* pl = &a;
-
- float* pf = &a;
-
- double* pd = &a;

总结:指针的类型决定了指针向前或向后走一步有多大(距离)
- #include
- int main()
- {
- int n = 0x11223344;
- char* pc = (char*)&n;
- int* pi = &n;
- *pc = 0;//重点在调试的过程中观察内存的变化
- *pi = 0;//重点在调试的过程中观察内存的变化
- return 0;
- }
总结:指针类型决定了,对指针解引用的时候有多大权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针解引用就能访问四个字节
概念:野指针就是指针指向位置是不可知的(随机的,不正确的,没有明确限制的)
- #include
- int main()
- {
- int* p;
- //p没有初始化,就意味着没有明确的指向
- //一个局部变量不初始化的话,放的是随机值
- *p = 10;//非法访问内存了
- return 0;
- }
- #include
- int main()
- {
- int arr[10] = { 0 };
- int* p = arr;
- int i = 0;
- for (i = 0; i <= 11; i++)
- {
- //当指针范围超出数组arr的范围时,p就是野指针
- *(p++) = i;
- }
- return 0;
- }
- #include
- int* test()
- {
- int a = 10;
- //a为局部变量,函数开始时创建,函数结束时销毁
- return &a;
- }
- int main()
- {
- int* p = test();
- *p = 20;
- //此时p指向的空间已销毁(被释放),不属于当前程序,此时指针p就为野指针
- return 0;
- }
- 指针初始化:
- 注意指针是否越界
- 指针指向被释放空间时置为NULL(空指针)
- 指针使用之前应检查其有效性
这里展示几个代码:
比较以下代码,并注意注释的内容:

函数栈帧与销毁:


总结:
- #include
- int main()
- {
- int arr[10] = { 0 };
- int i = 0;
- int n = sizeof(arr) / sizeof(arr[0]);//计算出数组中元素的个数
- /*for (i = 0; i < n; i++)
- {
- arr[i] = 1;
- }*/
- int* p = &arr[0];
- for (i = 0; i < n; i++)
- {
- *p++ = 1;//*(p+i)=1
- }
- return 0;
- }
观察下图:
可以很直观的得出:数组中两个指针相减得到的是指针和指针之间元素的个数
注意:
- 不是所有指针都能相减
- 指向同一块空间的两个指针才能相减!
例题:编写函数(不允许创建临时变量),求字符串的长度(三种方法)
- //循环
- #include
- int my_strlen(char* n)
- {
- int count = 0;
- while (*n != '\0')
- {
- count++;
- n++;
- }
- return count;
- }
- int main()
- {
- int len = my_strlen("lover");
- printf("%d", len);
- return 0;
- }
- //递归
- #include
从 - int my_strlen(char* n)
- {
- if (*n != '\0')
- {
- return 1 + my_strlen(n + 1);
- }
- else
- {
- return 0;
- }
- }
- int main()
- {
- int len = my_strlen("lover");
- printf("%d", len);
- return 0;
- }
- //指针-指针
- #define _CRT_SECURE_NO_WARNINGS
- #include
- int my_strlen(char* n)
- {
- char* np = n;
- while (*n != '\0')
- {
- n++;
- }
- return n - np;
- }
- int main()
- {
- char arr[] = "study";
- int len = my_strlen(arr);
- printf("%d", len);
- return 0;
- }
(3)指针的关系运算:
- #include
- #define A 5
- int main()
- {
- int arr[10] = { 0 };
- int* p = &arr[A];
- for (p = &arr[A]; p > &arr[0];)
- {
- *--p = 0;
- }
- return 0;
- }
标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
- 数组名表示的是数组首元素地址(两种情况除外,数组章节讲了——sizeof,&)

(不必多说,数组那节都已经讲了)
二级指针变量用来存放一级指针变量的地址
观察下面代码:

指针数组是数组,是存放指针的数组(数组我们已经了解了整型数组,字符数组)
观察下列代码:
- #include
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- int arr[10];
- int* ap = &a;
- int* bp = &b;
- int* cp = &c;
- //parr是存放指针的数组,就是指针数组
- int* parr[10] = { &a,&b,&c };
- int i = 0;
- for (i = 0; i < 3; i++)
- {
- printf("%d\n", *(parr[i]));
- }
- return 0;
- }
可以用其打印二维数组:
- #include
- int main()
- {
- int arr1[4] = { 1,2,3,4 };
- int arr2[4] = { 2,3,4,5 };
- int arr3[4] = { 3,4,5,6 };
- int* parr[3] = { &arr1,&arr2,&arr3 };
- int i = 0;
- for (i = 0; i < 3; i++)
- {
- int j = 0;
- for (j = 0; j < 4; j++)
- {
- printf("%d", parr[i][j]);//相当于:arri[j]
- //parr[1]相当于arr1,也可以改为 *( *(parr+i)+j)
- //arr[i] <==> *(arr+i)
- printf("\n");
- }
- return 0;
- }
知识点:arr[i] <==> *(arr+i)