在正文开始之前,大家可以简单看看我之前写的C语言初阶之指针:http://t.csdn.cn/MaPEV
目录
1.字符指针
1.1第一种使用方法:指针类型为字符指针 char * ;
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
char ch = 'w';
char* pc = &ch;//pc 就是一个字符指针
*pc = 'a';//使用 * 解引用操作符来改变指针所指向的变量
return 0;
}
1.2第二种操作方法 :代表字符串中第一个字符的地址
int main()
{
char arr[] = "abcdef";
//创建一个数组,里面放了[a b c d e f]
char * p = "abcdef";//常量字符串——无法被修改,因此加一个const会更加完美
const char* p = "abcdef";
//本质上是把字符 a 的地址赋给指针 p
return 0;
}
证明如下:
1.3一道经典的面试题目
int main()
{
char arr1[] = "Hello world!";
char arr2[] = "Hello world!";
const char * arr3 = "Hello world!";
const char * arr4= "Hello world!";
if (arr1 == arr2)
printf("arr1 and arr2 are same!\n");
else
printf("arr1 and arr2 are not same!\n");
if (arr3 == arr4)
printf("arr3 and arr4 are same!\n");
else
printf("arr3 and arr4 are not same!\n");
return 0;
}
运行结果:
解释如下:
2.指针数组
指针数组其实就是数组,是存放指针的数组。
整型数组——存放整型的数组 int arr [10] = { 0 } ;
整型指针数组——存放整型指针的数组 int * arr [10] = { 0 } ;
字符数组——存放字符的数组 char arr [10] = { 0 } ;
字符指针数组——存放字符指针的数组 char * arr [10] = { 0 } ;
指针数组——存放指针(地址)的数组
1.指针数组举例:
int main()
{
char arr1[] = "abcdef";
char arr2[] = "hello world";
char arr3[] = "cuihua";
char * parr[] = { arr1,arr2,arr3 };
//parr就是指针数组
//数组名arr1,arr2,arr3相当于首元素地址
//要把这个三个存起来,得用指针
return 0;
}
2.用指针数组模拟二维数组
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* parr[] = { arr1,arr2,arr3 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
//法一:
printf("%d ", parr[i][j]);
//法二:
printf("%d ", *(parr[i] + j));//使用解引用操作符
}
printf("\n");
}
return 0;
}
3.数组指针
3.1数组指针的定义
数组指针其实就是指针,是存放数组的指针。
整型指针——指向整型变量的指针,存放整型变量的地址的指针变量 int * p
字符指针——指向字符变量的指针,存放字符变量的地址的指针变量 char * p
指针数组——指向数组的指针,存放数组的地址的指针变量 int (*p)
注意区分指针数组和数组指针
//注意:[]的优先级要高于 * 的
int* p1[10];//指针数组
//p1 先和 [] 结合,说明是一个数组
//然后存放的是指针
int(*p2)[10];//数组指针
//p2 先和 * 结合,说明p2是一个指针变量
//然后指向的是一个大小为10个整型的数组
//注意:[]的优先级要高于 * 的,必须加上()来保证 p2 优先于 * 结合
3.2数组名 VS &数组名
我们一定知道数组名表示首元素地址
但是有两个例外:
例外一:sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
例外二:&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
注意:虽然&arr 和 &arr[0] 打印的结果一样,但是类型不一样,这也就是我们要区分的原因。
证明如下:
此外,剩余其他地方,数组名均表示数组首元素地址。
3.3数组指针的使用
3.3.1利用数组指针打印数组元素的地址
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*p)[10] = &arr;
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%p\n", (*p)[i]);//[]的优先级要高于 * 的,必须加上()来保证 p2 优先于 * 结合
}
return 0;
}
3.3.2在二维数组传参时使用
二维数组传参,形参是二维数组的形式
void Print(int arr[3][4])
{
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
Print(arr);
return 0;
}
二维数组传参,形参是数组指针的形式
void Print(int(*p)[4])//用数组指针来接收
{
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ",*((*p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//二维数组本质上是一维数组的数组
Print(arr);//arr是数组名,数组名是首元素地址
//相当于传过去一维数组的地址
return 0;
}
4.数组传参和指针传参
4.1一维数组传参
一维数组传参,形参是数组的形式
void Print(int arr[5])
{
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[5] = { 0 };
Print(arr);
return 0;
}
一维数组传参,形参是指针的形式
void Print(int *arr)
{
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%p ", arr+i);
}
}
int main()
{
int arr[5] = { 0 };
Print(arr);
return 0;
}
4.2二维数组传参:见上面
4.3一级指针传参:
void Print(int *p)
{
printf("%d",*p );
}
int main()
{
int arr = 10;
int* p = &arr;
Print(&arr);
return 0;
}
一级指针传参时,可以接受什么参数? (实参)
int arr = 10;
int* p = &arr;
int arr[10] = { 0 };
Print1(&arr);//传变量的地址
Print2(p);//传指针变量
Print3(arr);//传数组的地址
4.4二级指针传参
void Print4(int ** p)
{}
void Print5(int **p)
{}
int main()
{
int num = 10;
int* p = #
int** pp = &p;
Print4(&p);
Print5(pp);
return 0;
}
二级指针传参时,可以接受什么参数?(实参)
int num = 10;
int* p = #
int** pp = &p;
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 11,22,33,44,55,66,77,88,99,100 };
int arr3[10] = { 111,222,333,444,555,666,777,888,999,1000 };
int* arr[3] = { arr1,arr2,arr3 };
Print4(&p);//一级指针的地址
Print5(pp);//二级指针
Print6(arr);//指针数组
5.函数指针
函数指针——指向函数的指针
数组指针——指向数组的指针
5.1函数的地址:
int Add(int x, int y)
{
return x + y;
}
int main()
{
//打印函数地址
printf("%p\n", Add);
printf("%p\n", &Add);
//函数名是函数的地址
//&函数名也是函数的地址
return 0;
}
5.2函数指针类型的书写
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int,int) = &Add;//使用函数指针变量来存放函数的地址
//* 表示 pf 是指针变量
//pf 的类型就是int (*) (int,int)
//即函数指针类型
return 0;
}
5.3使用指针调用函数
int Add(int x, int y)
{
return x+y;
}
int main()
{
int(*pf)(int, int) = &Add;
//直接调用函数来计算
int n = Add(3, 5);
printf("%d\n", n);
//使用指针变量来计算
int m = (*pf)(3, 5);//pf是指向那个函数的,使用*解引用操作符,来调用函数
//调用函数需要传参,在括号里面给值即可
printf("%d\n", m);
return 0;
}
运行结果:
5.4两个例子:
例一:
(*(void(*)())0)();
( * ( void (*) () ) 0 ) ();
void( *p )( ) p是一个函数指针
void(*)( )是函数类型转换( )括号里面放类型是在强制类型转换
即把0强行转换为void(*)()这种指针类型解引用这个函数,这个函数没有参数
所以后面那个括号里面没东西
例二:
void (*signal(int, void(*)(int)))(int);
void ( * signal (int, void (*) (int) ) ) ( int ) ;
函数指针类型
void ( * signal ( int, void (*) (int) ) ) ( int ) ;
signal函数的两个参数
void ( * signal ( int , void (*) ( int ) ) ) ( int ) ;
signal ( int , void (*) ( int ) ) 是指向函数signal 的函数指针变量
void ( * signal ( int , void (*) (int) ) ) ( int );
signal函数的类型是void (*)(int)
欲知后事如何,请持续关注我!!!!