C Language_0309 Notes_Pointer: Definition/& and */value transfer/function returns multiple values/return and pointer division of labor/common errors

Precursor knowledge: The format control character %p can output an address in hexadecimal format ; %lu can output an unsigned decimal integer address.

9.1.1 Address operation

Operator: &

  • &: Obtain the address of the variable, and its operation object must be a variable .

  • 32-bit, that is, the same when compiling and running under x86, the normal address under 64-bit is eight bytes, and int is four bytes)

#include<stdio.h>
int main()
{
    int i;
    printf("0x%x\n",&i);//0x开头,输出16进制数,因为c不会自动补上0x
    return 0;
}
//程序先给了一个warning,然后输出了0xbff12d70。
warning的提示是,如果想输出地址,不应该用%x而是%p,%p会自带0x开头输出十六进制的变量地址。
因此我们将上面打印一句改为 printf("%p",&i);

&unavailable address

  • Must be an explicit variable

//都不行!!!!! 这三种都不能编译,必须是一个明确的变量
p=(int)&(p+i);
p=(int)&(++i);
p=(int)&(i++);
  • &Cannot get the address of something without an address

Try & get the address

  • Variable address (tried before, works)

  • Addresses of adjacent variables (contiguous definitions) (addresses are also adjacent)

int i=0;//最好初始化这样能确定其地址
int p;
//相邻变量
printf("%p\n",&i);
printf("%p\n",&p);

//Hexadecimal c=12, so the address difference between the two variables is 4, which is the byte size of an int. We are compiling under a 32-bit architecture at this time, so it shows that the addresses of adjacent variables in memory are also adjacent.

result:

  • sizeof(&variable) (tried before, works)

  • The address of the array

  • The address of the array cell

  • Address of adjacent array cell

#include<stdio.h>
int main()
{
int a[10];
        printf("%p\n",&a);//0xbff8dd44
        printf("%p\n",a);//0xbff8dd44      数组变量的名字 试图把它当成地址输出
        printf("%p\n",&a[0]);//0xbff8dd44  取出a[0]的地址
        //printf("%p\n",a[0]); 结果:0000000000000001 视频里面没有这句
        printf("%p\n",&a[1]);//0xbff8dd48   a[0]和a[1]的地址相差4,为一个int的值。
    return 0;
}

9.1.2 Pointers

If the variable address can be taken out and then passed to a function, can the variable be accessed in the function through the variable's address?

Do you feel familiar: scanf("%d",&i);

Thinking: We pass an address to scanf, from which it can get the integer we input and put it in the variable i. So how does it do it? How does it save the address of the variable? What kind of variable can receive the address obtained by taking the address character?

pointer

concept:

  • A variable of pointer type is a variable that holds an address.

  • Usually p represents pointer (point)

int *p=&i;
//p是一个指针,指向一个int类型,并把i的地址交给p(也就是 p的值=i的地址
int i;
int* p=&i;//将i的地址交给p,或者说 p指向i,此时p的值=i的地址

*的写法:

  • 二者的意思都一样,都表示p是一个指针指向int,*p是int类型,q是一个普通的int型变量

int* p,q;//星号*靠近int
int *p,q;//星号*远离int

指针变量:

  • 指针变量的内存的地址,与之相对的,普通变量的值就是实际的值

作为参数的指针(函数中使用指针)

void f(int *p);
//函数在被调用时可以得到某个变量的地址
int i=0;
f(&i);
//在函数里可以通过这个指针访问外面的局部变量i

举例说明:

*运算符

  • 引入一个新运算符:*

  • *是一个单目运算符,用来访问指针的值所表示的地址上的变量

*p:访问对应地址上的变量

#include <stdio.h>
    void f(int *p);
    int main()
    {
        int i=33;
        f(&i);
    }
    void f(int *p){
        printf("p=%p\n",p);//p=000000000062FE1C
        printf("*p=%d\n",*p);//*p=33
    }
  • p是指针,保存地址的变量,p的值就是i的地址

  • *p:通过p这个指针,我们访问到了p所指的int i里面的值,*p的值就是i的值

  • printf中的*p作为一个整体可以看作一个整数 (int *p)

*p值的传递

  • 函数的调用时发生的参数的转移,是一种值的传递,传值进函数后就与原来变量没关系了。

  • 然而当传递进去的是地址时,就可以在函数内部访问外部变量,得以修改其值。

  • 修改*p相当于是修改i。

  • 如原变量为i=6,*p=&a;*p=5,则此时i的值更改为5.

*p可以做左值也可以做右值。

int k=*p;
*p=k+1;
  • 【*p】意思是我要取得p这个指针所指的变量。(访问指针的值所表示的地址上的变量

  • 左值放在赋值号左边,不是变量,而是值,实际上是表达式计算的结果。

a[0] =2;
*p =3;//因此如果*p为左值时,代表了将 右边的计算结果赋值给对应地址上的变量

指针运算符——& 与*

  • &是取得变量的地址

  • *是取得对应地址的变量

//从字面上来看,二者互为对方的逆过程。事实上二者确实是互为反作用

*&y--*(&y):对一个地址取对应的变量==y
&*y---&(*y):对一个指针取对应的地址==指针(因为存放变量的地址),也就是对 指针取地址还是指针

传入地址

int x;scanf("%d",x);

没写&,但是编译没报错。为什么

如果正好是32位架构,整数和地址所占字节一样大,编译器会认为这就是你传入的地址。因此scanf函数不能将你输入的值正确传入给变量,而是传到了别的地方。因此运行一定是会报错的。

9.1.3 指针的作用

指针应用场景1 :交换变量的值

void swap(int *pa,int *pb)
{
    int t=*pa;
    *pa=*pb;
    *pb=t;
}
  • 此时只需要传入两个地址即可完成交换,原理是相同的,但传入指针可以改变原始值。

定义函数返回多个值:

  • 正常函数只能返回一个值也就是说,其作用是返回多个值,且某些值只能通过指针带回。传入的参数是需要进行编辑的变量

指针应用场景2:在函数中与return分工返回值和状态

  • 一般用return0或-1等不属于有效范围内的值表示出错多在文件操作中出现)

  • 任何数值都是有效的话:函数通过return返回运算状态指针返回结果。

//两个整数作除法
#include<stdio.h>
int divine(int a,int b,int *result);
int main(void)
{
    int a=5;
    int b=2;
    int c;
 
    if(divine(a,b,&c))//看函数divine的返回值 即:ret
    {
        printf("%d/%d=%d\n",a,b,c); //用指针返回值
    }
return 0;
}
 
int divine(int a,int b,int *result)
{
    int ret=1;
    if(b==0) ret=0;//(除数是0) 失败
    else 
    {
        *result=a/b;
    }
    return ret;//成功返回1 失败返回0(除数是0)
}
  • 当被除数=0,即b=0时,函数会直接返回状态值ret为0,而函数又位于if条件处,此时不会输出任何值。当正常时就会将a/b=c输出。实现了分开返回值与状态。

  • 这种方法的适用条件是运算中可能会出错,在C++/JAVA等语言中可以采用异常机制来解决这个问题。

指针最常见的错误

  • 定义指针变量,但没有指向任何变量就使用了指针

int k;
k=12; //可以!!
——————
int *p;
*p=12;// 不可以!!!程序可能会崩溃!!给的不是地址 //程序大概率会出错,且具有不确定性。
————————
*p=5;
printf("%d",i);

Guess you like

Origin blog.csdn.net/Shmily_as33/article/details/129416845