C语言_0310笔记_指针:3个运算符*&[]/数组常量指针/const指针/指针+/*p++/遍历新花样/指针用途总结

9.1.4 指针与数组

小实验:

将变量传递到函数中,函数得到的是变量的值。将指针传递到函数中,得到的是地址。那么把数组传递进去呢?

结论:

  1. 在主函数中数组的sizeof就是每个数组元素占据的空间之和。而在函数中数组大小正好为一个地址/指针的大小。//warning信息提示说:函数里的数组sizeof返回的是int*的大小而不是int[]的大小

  1. 无论在主函数还是函数中,数组a的地址相同。也就是说传到函数里的a就是外面的数组。【是同一个东西】

  1. 在函数minmax中改变数组a[0]的大小,结果是主函数的a[0]的值也改变了

  1. 传递到函数的数组实际上是个指针!这也就解释了,为什么在函数的参数表中数组要留个括号,为什么在方括号里写上数组大小也没用。

  1. 那它既然是个指针,能不能在函数头写指针如何?//没问题!编译运行都ok!warning都没有

自定义函数 数组作为参数 怎么写?

以下四种写法等价:

数组变量是特殊的指针

//数组就是一个地址 指针指向数组第一个[0]的地址

  • 数组变量本身其实是一种地址

  • 在取数组地址时不需要用到&,直接写数组名就可以。

int a[10]; 
int *p=a; //数组就是一个地址 指针指向数组第一个[0]的地址
  • 但是在数组单元的地址时需要&,因为数组单元表示变量

  • ps:因此我们在第一节取地址符中 a等同于&a[0]

  • [ ]运算符可以对数组做,也可以对指针做

int min=1;
int *p=&min;//p的值为min的地址,此时p指向min所在的空间;
         
printf("*p=%d",*p);//p=1  //*p的意思是min地址上面的值 也就是1
printf("p[0]=%d",p[0]);//p[0]=1  输出的就是所指的地址上面的第一个整数。
//p[0]意思是p指向的min是一个数组min[1],(min[1]有效下标只有min[0])
//假设指向的是min[1],一个只有一项的数组。输出的就是所指的地址上面的第一个整数。
  • * 运算符可以对指针做,也可以对数组做

#include <stdio.h>
int main()
{
     int a[]={1,2};
     printf("*a=%d\n",*a);//*a=1  
//虽然a是数组,但想输出*a依然可以得出其值。直接当指针用就好了。
     return 0;
}
  • 数组变量是const(常量)的指针,所以不能被赋值

  • 这也就解释了为什么不能将一个数组直接赋值给另一个数组

int a[]={1,2,3};
int b[]=a;//这是不行的 int b[]看作int *const b; 常数不能被改变,不能代表别的数组
int *q=a;//这个是可以的 指针q指向a的首地址a[0]

数组是一个常量指针

9.1.5 指针与const

//本视频只适用于C99

  • const是一个修饰符,加在变量前面,这个变量就不能被修改。指针也是一个变量,然而指针指向的也是变量。这两者都可以加上const限制。

  • 指针是const

  • 指针不能修改,也就是不能再得到地址,绑定了!!

//*q=26 可以,因为*q指向的i不是const;但是如果q作运算(试图改变地址),是不可以的

  • 指针指向的变量是const

不能通过指针p修改i的值(通过p更改i的值,不行)

p指向别人,ok //p=&j;可以指向别的地址

i自增,赋值,ok//i不是const可以改变

变量可以直接操作,但不能通过指针间接操作//在指针内部不能去动指针所指向的值

这些变化的区别

  • 判断哪个被const了,就看const在*前面还是后面

  • const在*号前,表示指针指向的变量不能修改。即第一种和第二种含义一致。

  • const在*号后,表示指针不能被修改。

 int i;
const int *p1 = &i;//指针指向的变量不能修改
int const *p2 = &i;//指针指向的变量不能修改
int *const p3 = &i;//指针不能被修改

转换const与非const

什么时候用上呢?

  • 当要传递的参数的类型比地址还大的时候,这是常用的手段:既能用较少的字节数传递值给参数,又能避免函数修改外面的变量

const数组

const int a[]={1,2,3,4,5,6};//数组其实是常量指针,在前面再加const?
  • 数组变量已经是const的指针了(a不能指向别的数组/不能赋值其他)

  • 这里的const表明数组的每个单元都是const int

  • 所以必须通过初始化进行赋值

保护数组值

  • 当数组传递进指针时,传递的是数组地址,因此函数中可以修改数组的值

  • 为保护数组不受破坏,可以设置参数为const

int sum(const int a[],int length);

9.2.1 指针运算

指针加一?(数组)

char ac[]={0,1,2,3,4,5,6,7,8,9,};//之前一直是int  char也是整数类型
char *p = ac;
 
printf("p  =%p\n",p);//p是指针 指向地址 
printf("p+1=%p\n",p+1);
  • 两个地址相差1

  • 把数组从char换到int类型,两个地址相差4

  • 为何如此?很简单,char变量占据一字节而int类型占据4字节。指针加一,增加的是sizeof(char/int/double...)

给指针加一表示要让指针指向下一个变量。

在讲到数组和指针的关系时,我们提到可以将指针当作数组操作,也可以将数组当作指针操作

那么我们试试用*操作符。

*p等价于ac[0]
那么*(p+1)等价于ac[1]

因此*(p+n) 等价于 ac[n]

tips:如果指针不是指向一片连续分配的空间,比如数组,那么这种运算就没有意义了

指针运算

  • 这些算术运算可以对指针做

  • 指针加减一个整数:+、-、+=、-= (往前挪和往后挪的区别)

  • 指针递增或递减:++、--

  • 两个指针相减:

  • 此时得到的结果是不是这两个地址的差

  • 而是(地址差除以sizeof())//在这两个位置之间,有几个这样类型的东西在?

  • 注意要以%d输出结果

int ac[]={0,1,2,3,4,5,6,7,8,9,};
int *p = &ac[0];
int *p = ac;
//3句和4句 是一回事!!!!
        int ac[]={0,1,2,3,4,5,6,7,8,9,};
        int *p = &ac[0];
        int *p1= &ac[5];
         
        printf("p=%p\n",p);
        printf("p+1=%p\n",p+1);
        printf("p1-p=%d\n",p1-p);
        printf("p1=%d\n",p1);
        printf("*p1=%d\n",*p1);

//注意:对于指针来说,直接打印%p,p,输出的一定是地址;

//%p,p1-p0 输出的是地址差 在这两个位置之间,有几个这样类型的东西在?

//要输出值 %d,*p

*p++

  • ++的优先级要比*高

//因此先执行p++(取值后自增)然后取地址,但是由于++在调用后才执行

  • 所以其作用是,取出p的地址,再将p移动到下一位

  • 适用于数组类的连续空间操作(如遍历)

  • 在一些cpu上可以被直接翻译为一条汇编语言

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

现在的遍历操作:

int ac[]={1,2,3,4,5,6,-1};
int *p=&ac[0];
 
    //写法1
    for(p=ac;*p!=-1;p++)
    {
        printf("%d\n",*p);
    }
    //写法2
    for(p=ac;*p!=-1;)
    {
        printf("%d\n",*p++);
    }
    //写法3
    while(*p!=-1)
    {
        printf("%d\n",*p++);
    }

指针比较

  • <、<= 、==、 >、 >=、 != 都可以对指针做

  • 实际上是比较它们在内存中的地址。(指向a[0]的指针要比指向a[5]的指针小)

  • 数组中单元地址是线性递增的

0地址-null

  • 在计算机运行时会给所有进程分配一块虚拟内存,其特征是地址从0开始,但是0地址是不能随便碰的!0地址不能被写入,有些甚至不能读取。因此你的指针不应该具有0值.

  • 然而0地址可以用来表示一些特殊的东西:

  • 返回0值代表返回的指针是无效

  • 定义指针变量时先让指针指向0,这意味着指针没有被真正初始化

  • C语言定义了一个符号NULL来表示0地址(一些编译器不想让你用0来表示0地址)

指针的类型

  • 无论指向什么类型,所有的指针的大小都是一样的,因为都是地址

  • 指向不同类型的指针不能直接相互赋值,这是为了避免用错指针

指针强制类型转换

  • void*(是一个指针) 表示指针不确定指向什么东西,但是指向一块内存空间

  • 强制类型转换 //不要轻易尝试

int *p = &i;
void *q = (void*)p; 

//此处将p强制转换为void型指针。这并没有改变p指向的变量的类型,而是通过q去看指向的变量时,不再将i看作int类型而是void类型。

总结:指针用途

猜你喜欢

转载自blog.csdn.net/Shmily_as33/article/details/129435816