DAY9 C基础 指针

1.1 指针和一维数组

int arr[3];

&arr[0]:数组第一个元素的地址

arr:数组名表示数组的首地址,也就是第一个元素的地址arr = &arr[0]

&arr:表示整个数组的首地址

 

 

#include <stdio.h>
int main(int argc, const char *argv[])
{
    int arr[3]={11,22,33};
    printf("arr=%p\narr+1=%p\n",arr,arr+1);

    printf("&arr[0]=%p\n&arr[0]+1=%p\n",&arr[0],&arr[0]+1);
    printf("&arr=%p\n&arr+1=%p\n",&arr,&arr+1);

    //arr=&arr[0]
    //&arr
    int *p=arr;//p=arr
    for(int i=0;i<3;i++)
    {
    //    scanf("%d",&arr[i]);
    //    scanf("%d",arr+i);
    //    scanf("%d",&p[i]);
    //    scanf("%d",p+i);
        scanf("%d",p++);
        //arr++:错误:数组的首地址arr表示常量

    }
    //地址的等价关系:
 //&arr[i]==>arr+i==>&p[i]==>p+i==>p++
p=arr;
    for(int i=0;i<3;i++)
    {
    //    printf("%d\t",arr[i]);

    //    printf("%d\t",*(arr+i));

    //    printf("%d\t",p[i]);
    //    printf("%d\t",*(p+i));
        printf("%d\t",*p++);

    }
 //值的等价关系:
 //arr[i]==>*(arr+i)==>p[i]==>*(p+i)==>*p++
    return 0;
}

练习解读代码:
int a[5]={1,2,3,4,5};
int *p=&a+1;
printf("%d  ",*(a+1), *(p-1)); 
结果:2 5

值的等价关系:

arr[i]==>*(arr+i)==>p[i]==>*(p+i)==>*p++

地址的等价关系:

&arr[i]==>arr+i==>&p[i]==>p+i==p++

1.2 指针和一维字符数组

1> 指针指向一维字符数组的首地址【可以通过指针修改数组的内容】

        1.1 使用指针实现字符串的输入输出

        char str[] = "hello" ;

        char *p = str;  //p==str

        scanf ("%s",p);

        printf ("%s",p);

        1.2 指针指向不同的字符数组,地址不同

        char str[]="hello";//注意:数组长度在输入时防止越界

        char  *p=str;//p==str

        char  str1[]="hello";

        char  *p1=str1;

        printf ("p=%p \n  p1=%p \n " ,p ,p1);

        *(p+1) = 'K';//可以通过指针改变数组的内容

        printf("p=%s\n",p);

2> 指针直接指向字符串常量的首地址【不可以通过指针修改字符串的内容】

        char *q="hello";

        char *q1="hello";

        printf("q=%p q1=%p\n",q,q1);//输出地址一样,指向只读区的字符串常量的首地址         //         *(q+1)='Q';//段错误

        //           printf("q=%s\n",q);

 1.3 指针和二维数组

&arr[0][0]:第一行第一列元素的地址

arr[0]:等价于一维数组数组名,列偏移,偏移的是一个元素字节的大小

&arr[0]:等价于一维数组数组名取地址,行偏移,偏移的是一整行字节的大小

arr:行偏移,偏移的是一整行字节的大小

&arr:偏移的是整个数组

 

 

练习:使用数组名行列地址转换的输出
 //表示2行3列的元素
/*    arr :第一行
    arr+1: 第二行的行地址
    *(arr+1): 表示把第二行的行地址转换为列 arr[1]
    *(arr+1)+2:2行3列的地址

    *( *(arr+1)+2 ):2行3列的值
    *( arr[1] +2 )*/
    
    int arr[2][3];
    for(int i=0;i<2;i++)
    {
    for(int j=0;j<3;j++)
    {
//    scanf("%d",&arr[i][j]);
//    scanf("%d",*(arr+i)+j); 重点
       scanf("%d",arr[i]+j);
    不建议
    }
    }
    for(int i=0;i<2;i++)
    {
    for(int j=0;j<3;j++)
    {
    //    printf("%d\t",arr[i][j]);
    //    printf("%d\t",*(*(arr+i)+j));
        printf("%d\t",*( arr[i] +j ));
    }
    printf("\n");
    }

地址等价:&arr[i][j] ===> *(arr+i)+j ===> arr[i]+j

值的等价:arr[i][j]  ===>  *(*(arr+i)+j)  ==>  *( arr[i] +j )


1.3.1 指针和二维数组结合

#include <stdio.h>
int main(int argc, const char *argv[])
{
    int arr[2][3]={11,22,33,44,55,66};
    int (*p)[3]=arr;   //p=arr
    printf("p=%ld\n",sizeof(p));
    for(int i=0;i<2;i++)
    {
    for(int j=0;j<3;j++)
    {
    //&arr[i][i] *(arr+i)+j  arr[i]+j
    //    scanf("%d",&p[i][j]);
    //    scanf("%d",*(p+i)+j);//重要
    //    scanf("%d",p[i]+j);
        scanf("%d",*p+j);//不建议,理解
    }
    p++;
    }
p=arr;
    for(int i=0;i<2;i++)
    {
    for(int j=0;j<3;j++)
    {
    //    printf("%d\t",p[i][j]);
    //    printf("%d\t",*(*(p+i)+j));//重要
    //    printf("%d\t",*(p[i]+j));
        printf("%d\t",*(*p+j));//不建议
    }
    p++;
    printf("\n");
    }
    return 0;
}
练习1:通过数组指针计算二维数组最大值和第二最大值
int main(int argc, const char *argv[])
{
    int arr[][3]={66,22,66,44,55,66};
    int line=sizeof(arr)/sizeof(arr[0]);//行
    int row=sizeof(arr[0])/sizeof(arr[0][0]);//列

    int (*p)[3]=arr;   //p=arr
    printf("p=%ld\n",sizeof(p));
    
    //先最大值,行列下表
    int max=**p;
    int maxi,maxj;
    int second=**p;
    for(int i=0;i<line;i++)
    {
        for(int j=0;j<row;j++)
        {
            if(max<*(*(p+i)+j))
            {
                max=*(*(p+i)+j);
                maxi=i;
                maxj=j;
            }
            if(second > *(*(p+i)+j))
            {
                second=*(*(p+i)+j);
            }
        }
    }
    //计算第二个最值

    for(int i=0;i<line;i++)
    {
        for(int j=0;j<3;j++)
        {
            //if(maxi==i && maxj==j)
            if(max== *(*(p+i)+j) )
            {
                continue;
            }
            if(second <*(*(p+i)+j))
            {
                second=*(*(p+i)+j);

            }
        }

    }
    printf("最大值时:%d 第二大值时:%d\n",max,second);

1.4 数组指针

本质上就是一个指针,主要用来指向二维数组的地址,或者做参数

定义格式:数据类型 (*指针变量名)[常量表达式] ()>[]>*

数据类型:基本数据类型[int float char..],构造数据类型[struct,union,数组]

指针,void

指针变量名:满足命名规范

()[]: 不可以省略

常量表达式:二维数组的列数

int arr[line][row];

int (*p)[row];

1.5 指针数组

本质上是一个数组,表示存储多个指针,满足数组的使用方式

定义格式:数据类型 *数组名[常量表达式] []>*

int *p[3]

数据类型:基本数据类型[int float char..],构造数据类型[struct,union,数组]

指针,void

数组名:满足命名规范

[]: 不可以省略

常量表达式:表示指针的个数

#include <stdio.h>
int main(int argc, const char *argv[])
{
    //1>指针数组指向多个变量的地址
    int a=11,b=22,c=33,d=44,e=55;
    int *p=&a;
    int *p1=&b,*p2=&c,*p3=&d,*p4=&e;

    int *q[5]={&a,&b,&c,&d,&e};
    //q[0]=&a *q[0]
    //q[1]=&b

    printf("sizeof(q)=%ld\n",sizeof(q));
    printf("a=%p  b=%p\n",&a,&b);
    for(int i=0;i<5;i++)
    {
        printf("q[%d]=%p\n",i,q[i]);
        printf("%d\t",*q[i]);
    }
    //2>指针数组指向多个数组的地址
    int arr1[]={1,2,3};
    int arr2[]={4,5,6};
    int arr3[]={7,8,9};
    
    int *s[3]={arr1,arr2,arr3};
    //s[0]=arr1
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            printf("%d\t",*(s[i]+j));
        }
    }
//3>指针数组指向多个字符串常量的地址
    char *m3="hello";
    char *m1="word";
    char *m2="aaa";
    char *m[3]={"hello","word","gsduwyfu"};
    for(int i=0;i<3;i++)
    {
     printf("%s\n",m[i]);
    }

1.6 多级指针

一级指针:存储普通变量的地址

二级指针:存储一级指针的地址

三级指针:二级指针的地址

.....

定义格式: 数据类型 **指针变量名

注意:*的个数不限

 

#include <stdio.h>
int main(int argc, const char *argv[])
{
    int a=11;
    int *p=&a;
    int **q=&p;
    int ***s=&q;
    printf("***s=%d\n**q=%d\n*p=%d\n",***s,**q,*p);
    printf("p=%p\n*q=%p\n**s=%p\n",p,*q,**s);
    return 0;
}

1.7 void和指针

定义格式: void *指针变量名

通用类型指针,它可以指针任何一种类型的地址,可以指向任何一块空间,但是

在使用时,必须要进行强制转换。

    int a=11;
    float b=1.1;
    char c='a';
    void *p=&a;
    printf("p=%p  *p=%d\n",p,*(int *)p);
    p=&b;
    printf("p=%p  *p=%f\n",p,*(float *)p);
    p=&c;
    printf("p=%p  *p=%f\n",p,*(char *)p);

1.8 const和指针

1> const修饰的变量不可以改变值

2> const修改的全局变量在.ro段

3> const修改的局部变量在栈区

4> const和指针

const int *p: *在const的右边,const修饰的是值,值不可以改变,地址可以改变

int const *p:*在const的右边,const修饰的是值,值不可以改变,地址可以改变

int * const p:*在const的左边,const修改的是地址,值可以改变,地址不可以改变

const int * const p:const修改的是地址和值,值不可以改变,地址不可以改变

#include <stdio.h>
int main(int argc, const char *argv[])
{
1> 认识argc和argv
    //argc:命令行输入参数的个数
    //argv:指针数组,接收命令行输入的字符串
    printf("argc=%d",argc);
    for(int i=0;i<4;i++)
    {
    printf("%s\t",argv[i]);
    }
    

#if 0
    //const int a=10;
    //a=100;
 
 2>const int *p: *在const的右边,const修饰的是值,值不可以改变,地址可以改变
     
    int a=10;
    int b=100;
    const int *p=&a;
//    *p=100;//改变值
    p=&b;
    printf("*p=%d\n",*p);

 3>int const *p:*在const的右边,const修饰的是值,值不可以改变,地址可以改变
    int const *p1=&a;
//    *p1=b;//改变值:报只读的错误
    p1=&b;
    printf("*p1=%d\n",*p1);

4>int * const p:*在const的左边,const修改的是地址,值可以改变,地址不可以改变
    int *const p2=&a;
    *p2=9999;
//    p2=&b;改变地址:报只读的错误
    printf("*p2=%d\n",*p2);

 5>const int * const p:const修改的是地址和值,值不可以改变,地址不可以改变
    const int * const p3=&a;
//    *p3=b;
    p3=&b;
    printf("*p3=%d\n",*p3);
#endif
    return 0;
}


作业:

练习1:使用指针实现两个字符串的比较【非函数实现】

 

练习2:使用指针实现字符串连接【非函数实现】

 

练习3:使用指针实现字符串逆置【纯指针】

char *p=str;

p

char *q=str+strlen(str)-1

abcde

0x10

i j

 

练习4:通过数组指针二维数组实现杨慧三角

if(j==0 || i==j)

{

arr[i][j]=1;

*(*(p+i)+j)=1;

}

else

{

arr[i][j]=arr[i][j-1]+arr[i-1][j-1]

*(*(p+i)+j-1)

}

 

练习5:通过数组指针实现二维数组转置[选做]

int arr[2][3]={1,2,3,4,5,6}

1 2 3

4 5 6

int brr[3][2]

1 4

2 5

3 6

brr[0][0]=arr[0][0]

brr[1][0]=arr[0][1]

brr[2][0]=arr[0][2]

brr[j][i]=arr[i][j]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值