C基础:指针

1.指针基本用法

1.1指针概念

地址:内存中每个字节单位都有一个编号(一般用十六进制表示)

指针:指针就是地址

指针变量:用于存放地址的变量就叫做指针变量

普通变量:

指针变量:

1.2 格式

存储类型 数据类型 *指针变量名;

数据类型: 代表指针所指空间存放的数据的数据类型

int *p; //定义了一个指向int类型数据的指针变量p

访问指针所指空间的内容时用取内容运算符*

那么变量p存放的就是a的地址,q变量存放的是b的地址。

通过运算符*就可以访问地址所表示空间里面内容。

那么变量p存放的就是a的地址,q变量存放的是b的地址。

通过运算符*就可以访问地址所表示空间里面内容。

指针与所指变量之间的关系如下图:

int i=3;

int *i_pointer=&i;

1.3 指针操作符

&: 取地址: 取变量的地址

*: 取内容: 取地址里面的内容

*&a = a; //*和&是互逆运算(可以抵消)

&*a; //错误 (原因:运算符优先级)

1.4 初始化和赋值

指针变量在使用前不仅要定义还要初始化,未初始化的指针变量不能随便使用,不然会产生野指针。

(1) 将普通变量的地址赋值给指针变量

int a = 1;
int *p = &a;
//或者
int a = 1;
int *p;
p = &a;

(2)将数组的首地址赋值给指针变量

int a[3] = {1,2,3};
int *p = a;//此时*p的内容是a[0]
(3)将指针变量里面保存的地址赋值给另一个指针变量
int *p = NULL;//NULL为空地址,可将指针指向空地址,令其成为空指针
int *q = p;
//或者
int *q;
q = p;

2.指针运算

2.1 算数运算:+ -

(1)对指针加减操作其实是让指针向前或向后移动

char s[32] = "hello";
    char *p = s;
    printf("%c\n", *p); //h
    p++;                //让指针向高地址方向移动一个数据单位,指针指向发生改变
    printf("%c\n", *p); //e
    p--;                //让指针向低地址方向移动一个数据单位,指针指向发生改变
    printf("%c\n", *p); //h

    p = p + 2;          //让指针向高地址方向移动两个数据单位,指针指向发生改变
    printf("%c\n", *p); //l

p+n: 访问高地址方向的第n个数据的地址,指针指向不改变。

p-n: 访问低地址方向的第n个数据的地址,指针指向不改变。

(2)指针偏移字节

偏移了多少字节 = 偏移量*sizeof(数据类型)

两个地址之间的差= 两个地址之间相隔元素的个数

p-q = 直接按相隔元素个数

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

    printf("%ld\n", q - p);  //5

验证了两个指针相减的结果是一个整数而不是地址量,代表两个指针相隔多少个元素

2.2 关系运算 < > == !=

指针之间关系运算比较的是它指向地址的高低

指向高地址的指针大于指向低地址的指针

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

    if (q > p)
        printf("q>p\n");

注意:指向不同类型的数组指针关系运算没有意义,指向不同区域的指针关系运算也没有意义(同一个数组间进行比较)

3.指针的大小

计算指针变量大小:siezof(指针变量名);

char *p1;
    int *p2;
    float *p3;
    double *p4;

    printf("%ld\n", sizeof(p1));//8
    printf("%ld\n", sizeof(p2));//8
    printf("%ld\n", sizeof(p3));//8
    printf("%ld\n", sizeof(p4));//8

总结:

(1)32位操作系统,指针大小4字节,64位操作系统,指针大小8字节

(2)内存地址是固定的,但是变量的地址不固定的(栈区变量随机分配)

(3)指针类型根据指针指向空间的数据类型

4.指针修饰

4.1 const常量化

注意:const定义变量时必须在定义的时候就给它赋初值。

(1)修饰普通变量

修饰局部变量:

const int a=10;

或者:int const a=10;

此时a只读,不可以修改。但是可以通过指针修改。

a=20; //报错:error: assignment of read-only variable ‘a’

int *p=&a;

*p=20; //可以用指针间接修改,会报警告。

修饰全局变量:

放在常量区,不能通过指针修改,会报段错误。

(2)修饰指针指向的内容

修饰*p,指针指向的内容不能修改,但是指针的指向可以修改。

const int *p;

int const *p;

(3)修饰指针的指向

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

4.2 void

1.不允许修饰普通变量: void a; //错误!!

2.可以修饰指针: void *p; //此时p是一个任意类型的指针

使用场景:函数传参或函数返回值。例如malloc函数的返回值。

注意: 通过void型指针进行取内容时,需要对地址进行强转。

转换方式:

强制转换: (int *) p 为右值。

4.3 大小端

在计算机进行超过1字节数据进行存储时,会出现存储数据顺序不同的情况即大小端存储

大端:数据的低位存储在高地址位,数据的高位存储在低地址位,大端字节序称为MSB

小端:据的低位存储在低地址位,数据的高位存储在高地址位,小端字节序称为LSB

举例: 存储数据0x12345678 起始地址0x4000

        地址:0x4000 0x4001 0x4002 0x4003

        小端:0x78 0x56 0x34 0x12

        大端:0x12 0x34 0x56 0x78

5.二级指针

5.1 格式

存储类型 数据类型 **指针变量名;

p指向了a, q指向了p也就是等于p的地址。

访问a的值,a的地址:

a的值

a的地址

p的地址

a

&a

&p

*p

p

q

**q

*q

6.指针和数组

6.1 两种访问方式

直接访问:按变量的地址存取变量的值 (通过数组名访问)

间接访问:通过存放变量地址的指针访问 (通过指针访问)

6.2 指针和一维数组

6.2.1 用法

int a[5] ={1,2,3,4,5}; //a数组的首地址

int *p=a;

通过数组名直接访问:

元素:a[i] 和 *(a+i)

地址:&a[i] 和 a+i

通过指针间接访问:

元素:p[i] *(p+i)

地址:&p[i] p+i

6.2.2 ++和*的运算方法

1.++和*是单目运算符

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

3.++在在前先++再取值,++在后先取值再加加。

4.++结合内容则内容加加,++结合的是指针那么则指针加加。

6.3 指针和二维数组

6.3.1 二维数组数组名表示

例如:

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

a是数组名,表示第一行的地址,a+1表示第二行的地址。

在行地址前面加*表示将行地址降级为列地址。

*a: 表示第一行第一列的地址

*a+1: 表示第一行第二列的地址

*(a+1): 表示第二行第一列的地址

*(a+1)+1: 表示第二行第二列的地址

元素:

a[i][j]

*(*(a+i)+j)

*(a[i]+j)

地址:

&a[i][j]

*(a+i)+j

a[i]+j

7.数组指针

7.1 定义

本质还是指针,指向的是数组。 (又称行指针)

7.2 格式

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

例如:

int a[2][3] = {1,2,3,4,5,6}; //a的类型int (*)[3]

int (*p)[3] = a;

p的类型也是 int (*)[3], 运算要3个3个运算

p可以代替a进行元素访问,但是本质不同,p是指针变量,a是地址常量。

访问地址:

&p[i][j]

p[i]+j

*(p+i)+j

访问元素:

p[i][j]

*(p[i]+j)

*(*(p+i)+j)

7.3 大小

sizeof(p) = 8

因为本质还是指针,所以大小都是8字节。 如果32位系统是4字节。

8.指针数组

8.1 定义

所谓指针数组是指由若干个具有相同存储类型和数据类型的指针变量构成的集合。

其本质是数组,里面存放的是指针。

8.2 定义格式

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

指针数组名还是表示该数组的首地址

例如:

int *a[2];

8.3 应用

(1)用于存放普通变量的地址

例如:

int a=10,b=20,c=30;

int *p[3] = {&a,&b,&c};

访问b的值:

*p[1]

**(p+1) //*(p+1)代表p[1]

访问b的地址:

p[1]

*(p+1)

访问abc的值:

*p[i]

**(p+i)

访问地址:

p[i]

*(p+i)

(2)用于存放二维数组中每行第一列的地址 (列地址)

例如:

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

int *p[2] = {a[0], a[1]}; //或者*a, *(a+1)

访问地址:

&p[i][j]

p[i]+j

//例如:p[0]=a[0]=&a[0][0]

//再例如:p[1]+1: p[1]=a[1]=&a[1][0] ==>p[1]+1 = &a[1][1]

*(p+i)+j

//例如:*(p+1)+1: p+1 = &p[1] ==>*(p+1)=p[1]=a[1]=&a[1][0] ==>*(p+1)+1 =&a[1][1]

访问元素:

p[i][j]

*(p[i]+j)

*(*(p+i)+j)

(3)用于存放字符串

char *p[3] = {"hello", "world","666"};

//打印字符串
    printf("%s %s\n", p[1], *(p + 1));      //打印world
    printf("%s %s\n", p[0], *p);            //打印hello
    //p[i] *(p+i)

    //打印'd'这个字符
    printf("%c %c %c\n", *(p[1] + 4), *(*(p + 1) + 4), p[1][4]);
    //*(p[i]+j)  *(*(p+i)+j)  p[i][j]

打印字符还是这三个公式:*(p[i]+j) *(*(p+i)+j) p[i][j]

(4)命令行参数

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

{
printf("%d\n",argc);
printf("%s\n",argv[0]);
printf("%s\n",argv[1]);
return 0;
}

argv:就是一个指针数组,里面存放的是命令行传递的字符串

argc:表示argv指针数组里面存储数据的个数,即命令行传递字符串的个数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值