C Language_0310 Notes_Pointers: 3 operators *&[]/array constant pointer/const pointer/pointer+/*p++/new tricks for traversal/summary of pointer uses

9.1.4 Pointers and Arrays

Small experiment:

Pass a variable to a function, and the function gets the value of the variable. Pass the pointer into the function and get the address. What about passing the array in?

in conclusion:

  1. In the main function, the sizeof of the array is the sum of the space occupied by each array element. In the function, the array size is exactly the size of an address/pointer . //The warning message says: The array sizeof in the function returns the size of int* instead of the size of int[]

  1. Whether in the main function or in the function, the address of array a is the same. In other words, the a passed to the function is the external array . [ It’s the same thing]

  1. Changing the size of the array a[0] in the function minmax results in the value of a[0] in the main function also changing.

  1. The array passed to the function is actually a pointer! This also explains why there are brackets for the array in the parameter list of the function, and why it is useless to write the array size in square brackets.

  1. So since it is a pointer, how about writing a pointer in the function header ? //no problem! Compiling and running are all ok! There is no warning

How to write a custom function array as a parameter?

The following four writing methods are equivalent:

Array variables are special pointers

//The array is an address pointer pointing to the address of the first [0] of the array

  • The array variable itself is actually an address

  • There is no need to use & when getting the array address, just write the array name directly.

int a[10]; 
int *p=a; //数组就是一个地址 指针指向数组第一个[0]的地址
  • But & is needed when taking the address of the array unit , because the array unit represents a variable

  • ps: Therefore, a in the address character we take in the first section is equivalent to &a[0]

  • The [ ] operator can be used on arrays or pointers.

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类型。

总结:指针用途

Guess you like

Origin blog.csdn.net/Shmily_as33/article/details/129435816
Recommended