C语言基础知识(五)

指针运算

算术运算

int a[] = {1,2,3,4,5};
int *p = a;
//p++  和  p+1  都是什么意思

p++  和  p+1 都是什么意思

++p有赋值的动作,指针向高地址方向移动一个数据单位(int  4字节;char  1字节)指针的指向发生改变 

p+2 //指针访问高地址方向第1元素指针的指向不发生改变

int a[5]={2,13,4,5,6};
// char a[]="hello";
int *p=a;
printf("%p\n",p);
printf("%d\n",*p);
p++;//p=p+1			//指针向高地址方向移动一个数据单位(int  4字节;char  1字节),指针的指向发生改变
printf("%p\n",p);
printf("%d\n",*p);
int a[5]={2,13,4,5,6};
    // char a[]="hello";
    int *p=a;
    printf("%p\n",p);
    printf("%p\n",p+2);	 //指针访问高地址方向第n个元素,指针的指向不发生改变
    printf("%p\n",p);

同一个数组,两个地址之间的差值=相差元素个数

关系运算

<   >   ==   !=

同一个数组比较才有意义

高地址>低地址

练习

h

D

指针的大小

getconf LONG_BIT 查看操作系统位数

32操作系统 ,指针大小为4字节 1字节==8

816进制 4*8=32二进制 =4字节

64位操作系统 ,指针大小为8字节

练习

字符数字char a[]="1234";  ---》num=1234;(字符1234转成数字1234)

#include <stdio.h>

int main(int argc, char const *argv[])
{
    char a[] = "1234";
    char *p = a;
    int s = 0;
    while (*p != '\0')
    {
        s = 10 * s + *p - '0';  //将字符转为数字
        p++;
    }
    printf("%d\n", s);

    return 0;
}

编写一个程序实现功能:将字符串“Computer Science”赋值给一个字符数组,然后从第一个字母开始间隔的输出该字符串,用指针完成。结果:Cmue cec

 编写一个程序实现功能:将字符串“Computer Science”赋值给一个字符数组,然后将数组里的前后互换,实现倒序输出该字符串,用指针完成。结果:ecneicS retupmoC

#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    //Computer Science字符串交换顺序输出
    char str[] = "Computer Science";
    char *p = str;
    int n = strlen(str);
    char *t = &str[n - 1];
    char temp;
    for (int i = 0; i < n / 2; i++)
    {
        temp = *p;
        *p = *t;
        *t = temp;
        p++;
        t--;
    }
    puts(str);

    return 0;
}

循环输入一个五位数判断是否是回文数,当输入0时结束,使用指针完成。例如:12321是回文数

#include <stdio.h>

int main(int argc, char const *argv[])
{
    //用指针判断是不是回文
    int a[6] = {};
    int n = sizeof(a)/sizeof(int);
    for (int i = 0;i<n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]==0)
            break;
    }
    int *p = a;
    int *t = &a[n-2];
    for(int j = 0;j<n/2;j++)
    {
        if(*p==*t)
        {
            p++;
            t--;
        }
        else
        {
            printf("不是回文\n");
            return 0;
        }
        
    }
    printf("是回文\n");

    return 0;
}

指针的修饰

指针修饰

const void

const

const常量化 read-only(变为只读)

修饰普通变量,不能直接通过变量进行修改

const int a=5; //int const a=5;

a+=6; //错误(变为只读,无法修改)

可以通过指针修改

const int a=5;

int *p=&a;

*p=88;

printf("%d %d\n",a,*p);

修饰指针

int const *p; //const修饰*p 指针指向的内容不能修改但是指针指向可以修改

int a=5;

const int *p=&a;

1) *p=33; //错误

2int b=33;

    p=&b; //正确

修饰p

int * const p=&a; //const修饰p 指针的指向不能指针指向内容可以

int a=5;

int * const p=&a;

*p=33;

printf("%d %d\n",a,*p);

int const * const p ; // 既修饰了p又修饰了指针,指针的指向和指针指向的内容都不能更改。

void

void    不能修饰普通变量,修饰指针表示任意类型的指针

void *p;//任意类型的指针

一般在函数参数或函数返回值中用到

void *p=NULL;
    int a=5;
    p=&a;
    printf("%p %p\n",(int *)p,&a);	//强转只在当前一行有效
    printf("%d %d\n",*(int *)p,a);

大小端

大端:低地址里边存放高字节数据,高地址里边存放低字节数据

小端:低地址里边存放低字节数据,高地址里边存放高字节数据

0x12345678

大端:0x12  0x34  0x56  0x78 

小端:0x78  0x56 0x34   0x12 

电脑是小端存储

二级指针

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

二级指针存放一级指针的地址

格式:存储类型 数据类型 **指针变量名

                             int             **p;

int a=8;
int *p=&a;
int **q=&p;

访问a的值:    a    *p    **q

访问a的地址:&a   p      *q

访问p的地址:       q      &p

指针和数组

指针和一维数组

直接访问:通过数组名

间接访问:通过指针

int a[]={2,3,4,5,6};

int *p=a;

直接访问

地址

数组

元素

a

&a[0]

2

a[0]

*a

a+1

&a[1]

3

a[1]

*(a+1)

a+2

&a[2]

4

a[2]

*(a+2)

a+3

&a[3]

5

a[3]

*(a+3)

a+4

&a[4]

6

a[4]

*(a+4)

间接访问

地址

数组

元素

&p[0]

p

a

&a[0]

2

a[0]

*a

*p

p[0]

&p[1]

p+1

a+1

&a[1]

3

a[1]

*(a+1)

*(p+1)

p[1]

&p[2]

p+2

a+2

&a[2]

4

a[2]

*(a+2)

*(p+2)

p[2]

&p[3]

p+3

a+3

&a[3]

5

a[3]

*(a+3)

*(p+3)

p[3]

&p[4]

p+4

a+4

&a[4]

6

a[4]

*(a+4)

*(p+4)

p[4]

a和p本质不同:a是地址常量,不能被赋值;p是指针变量,可以被重新赋值

运算方法

1*和 ++都是单目运算符优先级相同

2单目运算符从右向左运算

(*p)++(*p)==内容内容++

*p++先算p++,由于++在后p*最后p++

*(p++)::同上

++*p:先算*p得到内容 ++内容

++(*p)同上

*++p先算++p,由于++在前p自加自加后的地址内容

*(++p)同上

 

补充:

char *p="hello";

//p栈区开辟4字节空间存放字符串常量"hello"首地址

//"hello"存放在常量区

二维数组

二维数组数组名表示第一行首地址

int a[2][3]={2,3,4,5};     //a:第一行首地址 a+1:第二行首地址

a行地址如果访问其中的(行地址和列地址级别不同,一行可以有多列),需要对他降级处理加 *

a: 第一行首地址

a+1: 第二行首地址

*a: 第一行第一列地址

int a[2][3]={2,3,4,5,6,7};
    printf("%p\n",a);	//第一行的首地址
    printf("%p\n",*a);	//第一行第一列的地址
    printf("%p\n",*a+1);	//第一行第二列的地址
    printf("%d\n",*(*a+1));	//取第一行第二列的内容

    printf("%p\n",a+1);		//第二行的首地址
    printf("%p\n",*(a+1));	//第二行第一列的地址
    printf("%p\n",*(a+1)+1);		//第二行第二列的地址
    printf("%d\n",*(*(a+1)+1));	//取第二行第二列的内容

地址

元素

a[0]

*a

a

2

a[0][0]

**a

*a[0]

a[0]+1

*a+1

3

a[0][1]

*(*a+1)

*(a[0]+1)

a[0]+2

*a+2

4

a[0][2]

*(*a+2)

*(a[0]+2)

a[1]

*(a+1)

a+1

5

a[1][0]

*(*(a+1))

*a[1]

a[1]+1

*(a+1)+1

6

a[1][1]

*(*(a+1)+1)

*(a[1]+1)

a[1]+2

*(a+1)+2

7

a[1][2]

*(*(a+1)+2)

*(a[1]+2)

访问a[i][j]地址

a[i]+j          *(a+i)+j

访问a[i][j]

*(a[i]+j)       *(*(a+i)+j)

数组指针

本质指针指向数组

格式存储类型 数据类型 (*指针变量名)[列数]

nt a[2][3]={2,3,4,5,6,7};
    int (*p)[3]=a;	//算的二维数组有几列,定义指针数组的时候就填几列
    printf("%p %p\n",a,p);
    printf("%p %p\n",a+1,p+1);

p可以代替a进行元素访问但是本质不同

地址

元素

p[0]

*p

a[0]

*a

a

2

a[0][0]

**a

*a[0]

p[0]+1

*p+1

a[0]+1

*a+1

3

a[0][1]

*(*a+1)

*(a[0]+1)

p[0]+2

*p+2

a[0]+2

*a+2

4

a[0][2]

*(*a+2)

*(a[0]+2)

p[1]

*(p+1)

a[1]

*(a+1)

a+1

5

a[1][0]

*(*(a+1))

*a[1]

p[1]+1

*(p+1)+1

a[1]+1

*(a+1)+1

6

a[1][1]

*(*(a+1)+1)

*(a[1]+1)

p[1]+2

*(p+1)+2

a[1]+2

*(a+1)+2

7

a[1][2]

*(*(a+1)+2)

*(a[1]+2)

访问a[i][j]地址

p[i]+j      *(p+i)+j

访问a[i][j]

*(p[i]+j)    *(*(p+i)+j)

数组指针小是4

用指针遍历二维数组

int a[2][3]={2,3,4,5,6,7};
    int (*p)[3]=a;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<3;j++)
        {
            printf("%d\n",*(p[i]+j));		//*(*(p+i)+j)
        }
    }

指针数组

本质数组里边存放地址

格式存储类型 数据类型 *数组名[元素个数]

应用

  • 存放普通变量地址

int a=3,b=5,c=9;
int *p[3]={&a,&b,&c};
p[0]--->&a
p[1]--->&b
p[2]--->&c
访问b的值:
*p[1]	//p[1]访问指针数组的第二个元素,但是第二个元素是个地址,*p[1]
	*(*(p+1))	  //p+1访问的数组第二个元素的地址  *(p+1)取第二个元素的内容==&b;*(*(p+1))
访问b的地址:
	p[1]
	*(p+1)
  • 存放二维数组每一行第一列地址

int a[3][4]={2,3,4,5,6,7,8,9};
    int *p[3]={a[0],a[1],a[2]};

访问a[1][2]的值:
	*(p[1]+2)	p[1]访问数组中第二个元素(第二行第一列的地址),p[1]+2找到第二行第三列的地址,*(p[1]+2)
	*(*(p+1)+2)	//p+1找到数组中第二个元素的地址(a[1]的地址),*(p+1)==第二行第一列的地址,*(p+1)+2==第二行第三列的地址,*(*(p+1)+2)

访问a[1][2]的地址:
	p[1]+2
	*(p+1)+2

printf("%d\n",sizeof(p));	//12    3个指针
  • 存放字符串

char *p[3]={"hello","world","hqyj"};
打印world
    printf("%s\n",p[1]);
    printf("%s\n",*(p+1));
打印'd'
	*(p[1]+4)
	*(*(p+1)+4)    p+1找到数组中第二个元素的地址, *(p+1)取数组中第二个元素的内容(world的首地址),*(p+1)+4访问到 从w的位置移动4个字节到d的位置,*(*(p+1)+4)
	p[1][4]
  • 命令行参数

argv:就是一个指针数组,里面存放的是命令行传递的字符串
argc:表示argv指针数组里面存储数据的个数,即命令行传递字符串的个数
#include<stdio.h>
int main(int argc, char const *argv[])
{
    printf("%s\n",argv[1]);
    printf("%d\n",argc);
    return 0;
}

在linux命令行模式下可以在运行程序的时候一起输入。

  • 29
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值