1.指针基础知识
1.1 指针变量的定义和使用
- 指针也是一种数据类型,指针变量也是一种变量
- 指针变量指向谁,就把谁的地址赋值给指针变量
#include<stdio.h>int main()
{int a = 0;char b = 100;printf("%p,%p \n", &a,&b); // 打印a,b的地址// int*代表的是一种数据类型,int*指针类型,p为变量名。// 定义了一个指针类型的变量,可以指向一个int类型变量的地址int *p;p = &a; // 将a的地址赋值给变量p,p也是一个变量,值为内存编号printf("%d\n", *p); char *p1 = &b;printf("%c \n", *p1);return 0;
}
1.2通过指针间接修改变量的值
#include<stdio.h>// 通过指针间接改变变量的值int main()
{int a = 0;int b = 11;int *p = &a;*p = 100;printf("a = %d, *p = %d \n", a,*p);p = &b;*p = 22;printf("b = %d, *p = %d \n", b,*p);return 0;
}
1.3指针的大小
- 使用sizeof()测量指针的大小,得到的总是4和8
- sizeof()测的是指针变量指向存储地址的大小
- 在32 位平台,所有的指针(地址)都是 32 位(4 字节)
- 在64 位平台,所有的指针(地址)都是 64 位(8 字节)
1.4 野指针和空指针
指针变量也是变量,是变量就可以任意赋值,不要越界即可(32 位为 4 字 节,64 位为 8 字节),但是,任意数值赋值给指针变量没有意义,因为这样 的指针就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针 指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存 区域才会出问题。
#include<stdio.h>int main()
{// 野指针 ---1.没有一个有效的地址空间的指针int *p;*p = 1000;// 2. p变量有一个值,但该值不是可访问的内存区域int *p = 10; // 0-255留给操作系统*p = 2000;return 0;
}
但是,野指针和有效指针变量保存的都是数值,为了标志此指针变量没有指向 任何变量(空闲可用),C 语言中,可以把 NULL 赋值给此指针,这样就标志此 指针为空指针,没有任何指针。
1.5万能指针void
void *指针可以指向任意变量的内存空间:
#include<stdio.h>int main()
{// void * 指针int a = 345;void *p;p = &a;printf("%d\n", *(int*)p); // 进行强制类型转换return 0;
}
1.6const修饰指针
2.指针和数组
2.1数组名
数组名字是数组的首元素地址,但它是一个常量-----不可以被修改和赋值
2.2 指针操作数组元素
#include<stdio.h>int main()
{int a[]= {1,2,4,5,6,7,8,9,0};int n = sizeof(a) / sizeof(a[0]);for (size_t i = 0; i < n; i++){printf("%d", a[i]);}// 定义1个指针变量保存数组a的地址int *p = a;for(int i = 0; i < n; i++){p[i] = 2 * i;}for(int i = 0; i < n; i++){printf("%d", *(p+i));}return 0;
}
2.3指针加减运算
1)加法运算
- 指针计算不是简单的整数相加
- 如果是一个 int *,+1 的结果是增加一个 int 的大小
- 如果是一个 char *,+1 的结果是增加一个 char 大小
通过改变指针指向操作数组元素
#include<stdio.h>int main()
{int arr[] = {1,2,3,4,5,6,7,8,9};int i = 0;int n = sizeof(arr) / sizeof(arr[0]);int *p = arr;for(int i = 0; i < n; i++){printf("%d \n", *p);p++;}return 0;
}
2) 减法运算
#include <stdio.h>int main(){int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };int i = 0;int n = sizeof(a) / sizeof(a[0]);int *p = a+n-1; /// 指向数组的最后一个元素进行倒序排列for (i = 0; i < n; i++){printf("%d, ", *p);p--;}printf("\n");return 0;}
&数组名+1:------相当于加一个数组
3)指针加减指针:
指针加指针:error
指针-指针:对于数组来说:偏移过的元素个数
#include <stdio.h>int main() {int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};int *p2 = &a[5]; // 获取第3个元素(值为3)的地址int *p1 = &a[3]; // 获取第2个元素(值为2)的地址printf("p1 = %p, p2 = %p\n", p1, p2);int n1 = p2 - p1; // 指针相减,结果是元素个数差(2)printf("n1 = %d\n", n1);return 0;
}
3.指针实现的strlen函数
#include<stdio.h>#include<string.h>int mystrlen(char str[])
{int i = 0;while(str[i] != '\0'){i++;}return i;
}int main()
{char str[] = "hello";int ret = mystrlen(str);printf("ret = %d \n", ret);return 0;
}
4.指针的比较运算
#include<stdio.h>int main()
{int a[] = {1,2,4,5,6,7,8,9,0};int *p = &a[3];if(p>a){printf("成立\n");}else if(p<a){printf("不成立\n");}else{printf("==\n");}return 0;
}
对于普通变量来说比较语法允许无实际意义
对于数组来说:地址之间可以比较大小得出元素存储前的先后顺序
5.指针数组
指针数组,它是数组,数组的每个元素都是指针类型。本质上是一个二级指针
#include<stdio.h>// 指针数组1int main()
{int a = 10;int b = 20;int c = 30;int *p1 = &a;int *p2 = &b;int *p3 = &c;int *arr[] = {p1,p2,p3}; // 整形指针数组arr,存的都是整形地址printf("*(arr[0]) = %d\n",*(*(arr+0)));printf("*(arr[0]) = %d\n",*(arr[0]));printf("*(arr[0]) = %d\n",**arr); /// 二级指针// 指针数组2int a[] = {10};int b[] = {20};int c[] = {30};int *arr[] = {a,b,c};arr[0][0] = *(*(arr+0)+0); ///等价于 ==**arrreturn 0;
}
6.多级指针
- C 语言允许有多级指针存在,在实际的程序中一级指针最常用,其次是二 级指针。
- 二级指针就是指向一个一级指针变量地址的指针。
- 三级指针基本用不着,但考试会考。
#include<stdio.h>int main()
{int a = 10;int *p = &a;int **pp = &p;int ***ppp = &pp;printf("***ppp = %d \n", ***ppp);printf("**pp = %d \n", **pp);printf("*p = %d \n", *p);printf("a = %d \n",a);return 0;
}