c语言——指针进阶

本文介绍了C语言中的指针进阶知识,包括字符指针不能修改常量字符串,指针数组和数组指针的概念及使用,以及如何处理一维和二维数组。此外,还详细讲解了函数指针的用法,包括函数指针数组和回调函数的概念,并给出了相关示例代码。最后提到了void*类型在内存管理和类型转换中的作用。
摘要由CSDN通过智能技术生成

指针进阶

一,字符指针
1.
常量字符串的内容不能修改
这段代码应写成:
#include <stdio.h>
int main()
{
        const char * p = "abcdef" ; //"abcdef"是常量字符串,p中存的是a的地址;
        //*p='a';常量字符串的内容不能修改。
       printf( "%c\n" , *p);
       printf( "%s\n" , p);
        return 0;
}
2.
C/C++会将 常量字符串 存储到 单独的一块内存区域 ,p1,p2指向的是同一常量字符串的时候, 指向的同一块内存 ,所以地址相同。但是用相同的常量字符串来初始化多个数组 会开辟不同 的内存区域,所以arr1!=arr2.
3."abcdef"后还隐藏了一个'\0'
二,指针数组
三,数组指针
1.数组指针的格式
int main()
{
        char * arr[5] = { 0 };
        char * (*p)[5] = &arr;
        int arr1[10] = { 0 };
        int (*p1)[10] = &arr1;
        char arr2[10] = { 0 };
        char (*p2)[10] = &arr2;
        return 0;
}
--[]的优先级高于*,所以要加括号。
--char* [5],int [10],char [5]是被数组指针指向的数组的类型。
int main()
{
        int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
        int (*p1)[10] = &arr1;
       printf( "%d\n" , arr1[2]);
       printf( "%d\n" , (*p1)[2]);
       printf( "%d\n" , *(*p1 + 2));
        return 0;
}输出:3,3,3
--p1存的是整个数组的地址,*p1相当于取出了 整个数组==数组首元素的地址
但是就一维数组而言,这样太复杂了
对于一维数组可以这样写:
int main()
{
        int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
        int * p = arr1;
       printf( "%d\n" , p[2]);
       printf( "%d\n" , *(p + 2));
          printf( "%d\n" , *(arr + 2));
        return 0;
}输出:3,3
对于二维数组:
#include <stdio.h>
//参数为数组;
void print1( int arr [3][4], int x , int y )
{
        for ( int i = 0; i < x ; i++)
       {
               for ( int j = 0; j < y ; j++)
              {
                      printf( "%-3d " , arr [i][j]);  
              }
              printf( "\n" );
       }
       
}
//参数为指针
void print2( int (* p )[4], int x , int y )
{
        for ( int i = 0; i < x ; i++)
       {
               for ( int j = 0; j < y ; j++)
              {
                      printf( "%-3d " , *(*( p + i) + j));
              }
              printf( "\n" );
       }
}
void print3( int (* p )[4], int x , int y )
{
        for ( int i = 0; i < x ; i++)
       {
               for ( int j = 0; j < y ; j++)
              {
                      printf( "%-3d " , (*( p + i))[j]);
              }
              printf( "\n" );
       }
}
void print4( int (* p )[4], int x , int y )
{
        for ( int i = 0; i < x ; i++)
       {
               for ( int j = 0; j < y ; j++)
              {
                      printf( "%-3d " , p [i][j]);
              }
              printf( "\n" );
       }
}
int main()
{
        int arr[3][4] = { {1,2,3,4},{5,6,7,8},{10,11,12,13} };
       print1(arr, 3, 4);
       print2(arr, 3, 4);
       print3(arr, 3, 4);
       print4(arr, 3, 4);
        return 0;
} 输出:
1   2   3   4
5   6   7   8
10   11   12   13
1   2   3   4
5   6   7   8
10   11   12   13
1   2   3   4
5   6   7   8
10   11   12   13
1   2   3   4
5   6   7   8
10   11   12   13
*(*( p + i) + j)
--p+i表示跳几行--p是第一行整个数组的地址
--*(p+i)表示第i(从零开始)行数组首元素的地址
--*(p+i)+j表示第i行第j列元素的地址
(*( p + i))[j]
-- p+i表示跳几行--p是第一行整个数组的地址
-- *(p+i)表示第i(从零开始)行数组首元素的地址
-- (*( p + i))[j] 表示第i行第j列的元素
p[i][j]
--类比一维数组的传址
例题
int (*p[10])[5]
--p[10]表示有十个元素的数组, int (* )[5]表示元素类型--数组指针,指向由五个整型元素构成的数组
--类比int p[10]--int表示元素类型--int [10]表示数组类型
四,数组传参,指针传参
1.一维数组传参
void text( int arr [])
{ }
void text( int arr [10])
{ }
void text( int * arr )
{ }
void text1( int * arr1 [10])
{ }
void text1( int * arr1 [])
{ }
void text1( int ** arr1 )//传递首元素的地址--地址的地址
{ }
int main()
{
        int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
        int * arr1[10] = { 0 };
       text(arr);
       text1(arr1);
        return 0;
}
2.二维数组传参
void text( int arr [2][5])
{}
void text( int arr [][5])//可以省略行,不能省略列
{}
void text( int (* arr )[5])//传递首元素的地址--第一行数组的地址
{}
int main()
{
        int arr[2][5] = {0,1,2,3,4,5,6,7,8,9};
       text(arr);
        return 0;
}
3.一级指针传参
void text( int * p )
{}
int main()
{
        int arr[10] = {0,1,2,3,4,5,6,7,8,9};
       text(arr);
        int a = 0;
       text(&a);
        int * p = &a;
       text(p);
        return 0;
}
4.二级指针传参
void text( int ** p )
{}
int main()
{
        int * arr[10] = {0};
       text(arr);
        int a = 0;
        int * p = &a;
        int ** p1 = &p;
       text(p1);
       text(&p);
        return 0;
}
五,函数指针
1.&函数名==函数名
2.函数的指针
int (*p)(int,int)=Add;
--*p--指针变量
--int (int,int)--函数的类型
--()的优先级高于*,int *p(int ,int)表示p为函数名,参数为(int,int),返回值为int*的函数声明
有没有*都一样
3.函数指针数组--转移表
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
double Add( double x , double y )
{
        return x + y ;
}
double Sub( double x , double y )
{
        return x - y ;
}
double Mul( double x , double y )
{
        return x * y ;
}
double Div( double x , double y )
{
        return x / y ;
}
void menu()
{
       printf( "************************\n" );
       printf( "***1.Add********2.Sub***\n" );
       printf( "***3.Mul********4.Div***\n" );
       printf( "**********0.exit********\n" );
       printf( "请选择:>" );
}
int main()
{
        double x, y ;
        int input = 0;
       menu();
       scanf( "%d" , &input);
        double (*pfarr[])( double , double ) = { 0,Add,Sub,Mul,Div };
        do
       {
               if (input >= 1 && input <= 4)
              {
                      scanf( "%lf%lf" , &x, &y);
                      printf( "%lf\n" , pfarr[input](x, y));
              }
               else if (input < 0) printf( "请重新输入\n" );
               else if (input == 0) printf( "离开\n" );
       } while (input);
        return 0;
}
4.回调函数
  回调函数就是一个通过 函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
double Add( double x , double y )
{
        return x + y ;
}
double Sub( double x , double y )
{
        return x - y ;
}
double Mul( double x , double y )
{
        return x * y ;
}
double Div( double x , double y )
{
        return x / y ;
}
void menu()
{
       printf( "************************\n" );
       printf( "***1.Add********2.Sub***\n" );
       printf( "***3.Mul********4.Div***\n" );
       printf( "**********0.exit********\n" );
       printf( "请选择:>" );
}
void calc( double (* ph )( double , double ))
{
        double x, y;
       scanf( "%lf%lf" , &x, &y);
       printf( "%lf\n" , ph (x,y));
}
int main()
{
        int input = 0;
        do
       {
              menu();
              scanf( "%d" , &input);
               switch (input)
              {
               case 1:
              {
                      calc(Add);
                       break ;
              }
               case 2:
              {
                      calc(Sub);
                       break ;
              }
               case 3:
              {
                      calc(Mul);
                       break ;
              }
               case 4:
              {
                      calc(Div);
                       break ;
              }
               case 0:
              {
                      printf( "离开\n" );
                       break ;
              }
               default :printf( "请重新选择\n" );
              
              }
       } while (input);
        return 0;
}
Add,Sub,Mul,Div是回调函数
5.函数指针数组的指针
#include <stdio.h>
int Add( int x , int y )
{
        return x + y ;
}
int main()
{
        int (*p)( int , int ); //函数指针
        int (*parr[4])( int , int ); //函数指针数组
        int (*(*pparr)[4])( int , int )=&parr; //函数指针数组的指针
        return 0;
}
六.void* 
1.
void * 类型的指针变量仅保存指针的值(地址值),而忽略了指向数据的类型,因此 编译器不允许使用 “*”解引用运算,下标运算,加减指针运算.
• 作为任意类型数据的指针,即任意类型指针都可以 隐式转为 void * 
• void * 类型的变量,可超越指针兼容性, 隐式转为任意类型指针(自己不这么写)
int m = 3, n = 4;
int* q = malloc(m * n * sizeof( int));
void* t = q;
int(*p)[4] = t;
不报错
2.void的泛用类型参数
见qsort
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值