C语言指针


指针类型的意义:

1.指针类型决定了指针解引用操作符能访问几个字节: char* p能访问1个字节, int* p 能访问4个字节

2.指针类型决定了指针+1,-1,加的或者减的时几个字节:char* p;p+1,跳过一个字节。int* p; p+1,跳过四个字节。

int a = 0x11223344;
char* cp = (char*)&a;
int* ip = &a;
printf("%p\n",*cp);//00 00 00 44
printf("%p\n",*ip);//11 22 33 44

字符指针

在指针类型中将char*称为字符指针。

char a[] = "abcdef";
char* p = a;
printf("%s\n",a); //abcdef
printf("%s\n",p); //abcdef

const char* p1 = "abcdef";
const char* p2 = "abcdef";
if (p1==p2)
{
  printf("相同");//会进行打印,说明p1和p2指向同一块内存空间
}

指针数组

指针数组是用来存放指针的数组。即Elemtype* p[count],例:int* p[4](存放整形指针的数组)。

int a = 10;
int b = 20;
int *arr[2] = {&a, &b};
for (size_t i = 0; i < 2; i++)
{
  printf("%d\n", *(arr[i])); //10 20
}

int arr1[] = {1, 2, 3, 4};
int arr2[] = {5, 6, 7, 8};
int arr3[] = {9, 10, 11, 12};
int *parr[] = {arr1, arr2, arr3};
for (size_t j = 0; j < 3; j++)
{
  printf("%d\n",*(parr[j])); // 1  5  9
  printf("%d\n",*(parr[j] + 1));// 2  6  10  parr[j] + 1代表向后偏移一位
}

数组指针

数组指针就是用来存放数组的指针。

一维数组
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// arr -首元素地址
//&arr[0] -首元素地址,和上面意思相同
//&arr -数组的地址
int(*p)[10] = &arr;//存数组的地址 p就是数组指针

//取址打印 最简便的方法还是另 int *p = arr; 然后(*p + i) 来取各个元素
for (size_t i = 0; i < 10; i++)
{
  //方法一
  printf("%d\n",(*p)[i]);
  //方法二 *p == arr
  printf("%d\n", *(*p + i));
}

char* arr2[5];//字符指针
char* (*pa)[5]= &arr2; //存放字符数组指针
二维数组
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p)[3] = arr;//arr代表首元素的地址,
for (size_t i = 0; i < 2; i++)
{
  for (size_t j = 0; j < 3; j++)
  {
    printf("%d ", *(*(p + i) + j)); //*(p+i) == arr[i] == p[i] 表示第i行的数据 *(*(p+i) + j) == (*(p + i))[j] == p[i][j] 表示第i行j列的数据
  }
  printf("\n");
}

总结举例:

int arr[5]是一个5个元素的整形数组

int *parr1[10]是一个10个元素的类型为int*的指针数组

int (*parr2)[10]是一个数组指针,指向了一个有10个元素的数组,每个元素的类型是int

int (*parr3[10])[5]是一个数组,有10个元素,每个元素是一个指向5个元素的数组指针(即第一层是放着10个指针元素的数组,每个指针所指向的是一个包含5个int类型元素的数组)。

数组参数、指针参数

一维数组传参
//以下方法均可以接受到参数
void test(int arr[]){}
void test(int arr[10]){}
void test(int *arr){}

void test2(int *arr[]){}
void test2(int **arr){}
int main(){
    int arr[10] = {0};
    int *arr2[20] = {0};
    test(arr);
    test2(arr2);
    return 0;
}
二维数组传参
//二维数组传参时不能省略列

void test(int arr[][3]){}//正常运行
void test(int arr[2][3]){}//正常运行
void test(int arr[2][]){}//报错
void test(int arr[][]){}//报错
int main()
{
  int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
  
  test(arr);
  return 0;
}

传二维数组以指针形式接收

void test(int (*arr)[3]){} //(*arr)表示首元素的指针即arr[0]
int main()
{
  int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
  
  test(arr);
  return 0;
}
一级指针传参
void test(int *p){}
int main()
{
  int a = 10;
  int *p = &a;
  test(&a);
  test(p);//两个结果相同
  return 0;
}
二级指针传参
void test(int **ptr){}
int main()
{
  int a = 10;
  int *p = &a;
  int **pp = &p;
  test(pp);
  test(&p);//两个结果相同
  //也可以传指针数组
  int* arr[10] = {0};
  test(arr);
  return 0;
}

函数指针

函数指针就是指向函数的指针。

int test(int x){ return 0; }
void test2(char *content){ printf(content); }
int main(int argc, char const *argv[])
{
  int (*p)(int) = test; //这就将函数test的地址赋值给了p
  void (*p2)() = test2; //存储无返回值的函数
  //通过指针调用函数
  (*p2)("Hello World\n"); //可以打印出 Hello World
  //结果相同,均为函数test的地址值
  printf("%p\n",test);
  printf("%p\n",&test);
  return 0;
}
分析函数指针代码
void (*signal(int , void(*)(int)))(int);
//从内层往外层看,显然内部的signal为一个函数声明,第一个参数为int类型,第二个参数为函数指针类型(返回值为void 接收参数为int),而外层的void(* )(int)则也是函数指针,说明signal的返回值也为函数指针类型

//进行简化
typedef void(*pfun_t)(int);//将函数指针重定名为pfun_t
pfun_t signal(int,pfun_t);
创建函数指针的数组
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;
}
int main()
{
  int (*parr[4])(int, int) = {Add, Sub, Mul, Div};
  //调用函数
  for (size_t i = 0; i < 4; i++)
  {
    printf("%d\n",parr[i](2,3)); //5  -1  6  0
  }
  return 0;
}

回调函数

回调函数即用函数来调用其他函数。

int test1(int x, int y){ 
  printf("test1调用成功\n");
  return x+y; }
void test2(int (*pf)(int,int)){
  printf("test2调用成功,结果为:%d\n",pf(2,3));
}

int main(){
   int (*p)(int,int) = test1;
   test2(p); //两个结果都会打印.
}

void* p 类型的指针可以接受任意类型的地址。(但无法进行解引用,和加减等与和地址有关的操作!!!)

例:

int a = 1; void* p = &a;成立。

char b = 'a'; void* p = &b;成立。


文章作者: LsWorld
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LsWorld !
评论
  目录