C语言08--指针数组结合

 前言:

        这次的指针数组结合乃作者呕心沥血之作,大家翻翻进度条就知道了,内容十分干货,各位读者若能全部耐心解析读懂了,想必也能理解掌握C语言中的数组指针这两把利剑了。

指针数组结合:

指针数组

概念:他是一个数组,该数组中每一个元素的类型是指针。

语法:

int * arr[ 元素数量 ] ; // 整型指针数组
char * arr[ 元素数量 ] ; // 字符指针数组
float * arr[ 元素数量 ] ; // 浮点指针数组 
int * arr[ 元素数量 ] (int) ; // 函数指针数组

示例:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 123 , b = 456 , c = 789 , d = 111 , e = 222 ;

    // 指针数组
    int *  arr1 [ 5 ] = {&a , &b , &c , &d , &e } ; // 整型指针数组

    for (int i = 0; i < 5; i++)
    {
        printf( "arr1[%d]:%d\n" , i ,*arr1[i] );
    }

    // arr1[0][1] --》 *(arr1[0]+1)  -- > *(*(arr1+0)+1)
    printf("arr[0][1]:%d\n" , arr1[0][1] ) ;//得到数组首元素即*(&a+1),加一个&a大小,即指向&b,解引用得到456
    printf("**arr:%d\n" , **arr1 ) ;  // a = 123,arr1为数组首元素地址,解引用得到&a,再次解引用得到a的值123
    printf("**arr1+1:%d\n" , **arr1+1 ) ;  // a=124,同上,a的值加一得到124
    printf("**(arr1+1):%d\n" , **(arr1+1) ) ;  // b=456,arr1为数组首元素地址,+1偏移一个数组首元素地址大小,即指向数组第二个元素地址,解引用两次得到b的值
    printf("*(*arr1+1):%d\n" , *(*arr1+1) ) ;  // b =456,arr1为数组首元素地址,解引用得到&a,&a可以看作一个指针,+1偏移一个int地址大小,解引用得到b的值
    printf("*(*arr1+1):%d\n" , **(&arr1+1) ) ;  // 【越界】,&arr1为整个数组的地址,+1加一整个数组地址大小,指向数组之外,越界
    printf("**(*(&arr1+1)-1):%d\n" , **(*(&arr1+1)-1) ) ;  // e = 222,&arr1为整个数组的地址,+1加一整个数组的地址大小,解引用得到数组,指向数组
                                                            //末尾元素地址,-1减去一个数组元素地址大小,指向数组最后一个元素地址,两次解引用得到222
    

    char * arr2 [ 5 ] ; // 字符指针数组
    float *arr3 [ 5 ] ; // 浮点指针数组 
    // int *  arr4 [ 5 ] (int) ; // 函数指针数组

    
    return 0;
}

数组指针数组:

概念:他是一个数组,该数组中每一个元素都是指针,而这些指针指向的类型是数组类型。

语法:

type (* arr [5]) [N] ;

示例:

#include <stdio.h>


int main(int argc, char const *argv[])
{

    // 整型数组
    int arr1[2] ={1,2};
    int arr2[2] ={10,20};
    int arr3[2] ={100,200};


    // 整型数组指针
    int (*p1 )[2] = &arr1 ;
    int (*p2 )[2] = &arr2 ;
    int (*p3 )[2] = &arr3 ;

    // 整型数组指针数组
    int (* arr[3]) [2] = { p1 , p2 , p3} ;

    // arr[i] --> p1 
    // p1 = &arr1 
    // (*arr[i]) --> (*p1) --> (*&arr1) --> arr1
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            printf("(*arr[%d])[%d]:%d\n", i , j , *((**(arr+i))+j) );
            //(*arr[i])[j]  --> *((*arr[i])+j) --> *((**(arr+i))+j))
            //arr为数组首元素地址,+i加i个数组首元素地址大小,指向数组的第i+1个元素,第一次解引用得到数组的元素,即指针,再次解引用得到
            //指针指向的值,即一维数组,这时候得到一维数组arr1即首元素地址,+加上j个数组首元素地址大小,偏移j个元素,解引用得到一维数组的元素
            //这里会逐个打印出一维数组的全部元素
        }
        
    }
    
    

    return 0;
}

指针数组数组:

概念:他是一个数组,该数组中每一个元素都是数组,而这些数组中每一个元素都是指针。

语法:

 type * arr[3] [2] ;

数组指针:

概念:他是一个指针,该指针指向的是一个数组的类型

语法:

int (*ptr) [5]  ; // 一个指针,该指针指向拥有5个整型数据的数组 【整型数组指针】
char (*ptr) [5]  ; //  一个指向用于5个字符型的数组  【字符数组指针、 字符串数组指针】
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int arr [5] = {1,20,3,4,5};

    

    int (*ptr) [5] ; 
    ptr = &arr ;

    int * p = arr ;
    // p == arr ;

    // ptr = &arr ;
    // **ptr = **&arr = *arr = 1
    printf("**ptr:%d\n", **ptr); // 1,ptr解引用得到arr,arr为数组首元素地址,解引用得到数组首元素,即1

    printf("**ptr+1:%d\n", **ptr+1); // 2,同上,1+1=2

    // *(*ptr+1) == *(*&arr+1) = *(arr+1)
    printf("*(*ptr+1):%d\n", *(*ptr+1)); // 20,ptr解引用得到数组arr,arr为数组首元素地址,+1加一个数组首元素地址大小,解引用得到数组第二个元素

    printf("*(*(ptr+0)+1):%d\n", *(*(ptr+0)+1)); // 20,ptr解引用得到arr,arr为数组首元素地址,+1加一个数组首元素地址大小,解引用得到数组第二个元素
    printf("ptr[0][1]:%d\n", ptr[0][1] ); // 20,相当于*(*(ptr+0)+1),同上
    

    // 【拓展】 预习函数的形参中出现数组
    // 一下两种写法是等价的,第一种写法是用于强调(告诉使用者)
    // 函数pipe 需要的地址必须有两个以上整型的合法内存空间
    // int pipe(int pipefd[2]);  
    // int pipe(int * pipefd);


    char msg1[] = "Hello";
    char msg2[] = "World";
    char msg3[] = "WangDaNiang";
    char msg4[] = "ShiDaSao";
    char msg5[] = "!";

    char * arr1[5] = { msg1, msg2, msg3 ,msg4 , msg5};
    char *(* ptr1) [5] = &arr1;
    
    // 操作练习通过ptr1来实现一下操作:
    //  1. 数组以上所有的字符串 "Hello" , "World" , "!" , "!" , "!"
    for (int i = 0; i < 5 ; i++)
    {
        // ptr1 = &arr1 
        //(*ptr1) = arr1
        printf("arr1[%d]:%s\n" , i , (*ptr1)[i] );
        //&arr1为整个数组的地址,ptr解引用得到数组arr1,arr1为数组首元素地址,arr1[i]得到数组的元素
    }
    
    //  2.1  尝试修改某一个字符
    //  arr1[2][5]  ->  (*ptr1)[2][5]
    //  ptr1 = &arr1 
    (*ptr1)[2][5] = 'A';
    //&arr1为整个数组的地址,ptr解引用得到数组arr1,arr1[2][5]得到数组第三个元素的第六个元素
    printf("arr1[2]:%s\n" , arr1[2] ); 


    //  2.2 尝试把所有的小写字符转换为大写
    for (int i = 0; i < 5 ; i++)
    {
        for (int j = 0; j < 32 ; j++)
        {
            if ((*ptr1)[i][j] != '\0' && 
                    (*ptr1)[i][j] >= 'a' && 
                        (*ptr1)[i][j] <= 'z'  )
            {
                (*ptr1)[i][j] -= 32 ;
            }
            
        }
        
    }

    for (int i = 0; i < 5 ; i++)
    {
        // ptr1 = &arr1 
        //(*ptr1) = arr1
        printf("arr1[%d]:%s\n" , i , (*ptr1)[i] );
        //&arr1为整个数组的地址,解引用得到数组arr1,然后arr1[i]访问数组每个元素,打印出改变大小写后的每个字符串
    }
    

    // char * p1 = &"Hello" ;
    
    return 0;
}

指针数组指针:

概念:他是一个指针,该指针所指向的内存是一个数组的类型,该数组存储的指针类型的元素。

语法:

int * (*ptr) [5] ;

数组指针指针:

概念:他是一个指针,该指针指向的是另外一个指针,该指针指向的是数组的地址。

语法:

int (*(*ptr)) [5] ;
    • 为什么数组名不可以直接赋值
int arr[3];
arr = 123 ;  // 该操作在试图改变arr的地址 , 有明显的逻辑问题(语法错误)
arr[0] = 123 ;
*(arr+1) = 456 ;
    • 数组名为什么不能++
int arr [3];
arr ++ ;  // arr++  -》 arr = arr + 1;    加完之后等式两边不等,左
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值