1.指针是什么
指针也是一种变量,这种变量专门存储地址值。
int a = 100;
int* b = &a;
上面的代码很清晰,a是一个整形变量,值为100;b是一个指针变量,值是变量a的地址。变量和指针的类型必须相同。
解引用:
#include<stdio.h>
int main() {
int a = 10;
int* pa = &a;
//printf("%p\n", pa);
//printf("%p\n", &a);
*pa = 20; //*为解引用操作
printf("%d\n",a);
return 0;
}
20
2.指针和指针类型
int占4个字节,char 占1个字节,short占2个字节,double占8个字节。
指针类型有多种多样,int* ,float* ,char*等等,
2.1 指针+-整数
指针的类型决定了指针向前或者向后走一步有多大(距离)。
2.2指针的解引用
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如:
char*
的指针解引用就只能访问一个字节,而
int*
的指针的解引用就能访问四个字节
3.野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
要规避野指针!!!
4.指针运算
指针
+-
整数
指针
-
指针
指针的关系运算
5.指针与数组
数组名表示的是数组首元素的地址 。引用一个数组元素,可以用以下两种方法:
1. 下标法,如a[i]
形式;
2. 指针法,如*(a+i)
或*(p+i)
。其中 a 是数组名,p是指向数组元素的指针变量,其初值为p=a
;
6.二级指针
二级指针就是取一级指针的地址,一级指针就是取原来数字的地址。
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
** ppa = 30 ;// 等价于 *pa = 30;// 等价于 a = 30;
7. 字符指针
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char *str3 = "hello bit.";
const char *str4 = "hello bit.";
if(str1 ==str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 ==str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
这里
str3
和
str4
指向的是一个同一个常量字符串。
C/C++
会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1
和
str2
不同,
str3
和
str4
相同。
8.指针数组
指针数组是一个存放指针的数组
int* arr1 [ 10 ]; // 整形指针的数组char * arr2 [ 4 ]; // 一级字符指针的数组char ** arr3 [ 5 ]; // 二级字符指针的数组
#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
的类型是:
int(*)[10]
,是一种数组指针类型
数组的地址
+1
,跳过整个数组的大小,所以
&arr+1
相对于
&arr
的差值是
40
9.数组指针
数组指针是指向数组的指针
需要明确一个优先级顺序:()>[]>*,所以:
(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;
*p[n]:根据优先级,先看[],则p是一个数组,再结合,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。
int *p1[5];//指针的数组
int (*p2)[5];//数组的指针
10.数组参数、指针参数
10.1一维数组传参
#include <stdio.h>
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);
}
10.2二维数组传参
void test(int arr[3][5])//ok
{}
void test(int arr[][])//err
{}
void test(int arr[][5])//ok
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//err 一级指针啥也找不到
{}
void test(int* arr[5])//err 是个数组但找不到元素
{}
void test(int (*arr)[5])//ok 指针指向的数组
{}
void test(int **arr)//err 存放的是一级指针的地址
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}
10.3一级指针传参
#include <stdio.h>void print ( int * p , int sz ){int i = 0 ;for ( i = 0 ; i < sz ; i ++ ){printf ( "%d\n" , * ( p + i ));}}int main (){int arr [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };int * p = arr ;int sz = sizeof ( arr ) / sizeof ( arr [ 0 ]);// 一级指针 p ,传给函数print ( p , sz );return 0 ;}
10.4二级指针传参
void test ( char ** p ){}int main (){char c = 'b' ;char* pc = & c ;char** ppc = & pc ;char* arr [ 10 ];test ( & pc );test ( ppc );test ( arr ); //Ok?return 0 ;}
11.函数指针
void (*pfun1)(); //存储函数的地址
=&add
=add
12.函数指针数组
把函数的地址存到一个数组中,那这个数组就叫函数指针数组。
#include<stdio.h>
int my_strlen(const char* str) {
return 0;
}
int main() {
//函数指针数组
int(*pf[5])(const char*) = { &my_strlen };//数组内部存放的是函数的地址
return 0;
}
函数指针数组的用途:转移表-------例子:(计算器)
#include <stdio.h>
int add(int x, int y) {
return x + y;
}
int sub(int x, int y) {
return x - y;
}
int mul(int x, int y) {
return x * y;
}
int div(int x, int y) {
return x / y;
}
void meau() {
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf("*************************\n");
}
int main() {
int a, b, input, ret;
input = 1;
int (*p[5])(int x, int y) = { 0,add,sub,mul,div };
do {
meau();
printf("请选择操作:");
scanf_s("%d",&input);
if ((input >= 1) && (input <= 4)) {
printf("请输入数:");
scanf_s("%d %d", &a, &b);
ret = (*p[input])(a, b);
}
else
printf("输入有误\n");
printf("ret = %d\n", ret);
} while (input);
return 0;
}