C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误

C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第1张图片

前体知识:格式控制符%p可以输出十六进制格式的地址;%lu可以输出无符号十进制整数地址。

9.1.1 取地址运算

运算符:&

  • &:获得变量的地址,它的操作对象必须是变量

C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第2张图片
  • 32位,即x86下编译运行时相同,64位下正常的地址是八字节,int是四字节)

#include
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);

&不能取的地址

  • 必须是明确的变量

//都不行!!!!! 这三种都不能编译,必须是一个明确的变量
p=(int)&(p+i);
p=(int)&(++i);
p=(int)&(i++);
  • &不能对没有地址的东西取地址

试试&能取的地址

  • 变量地址(前面已试过,可行)

  • 相邻变量(连续定义)的地址(地址也相邻)

int i=0;//最好初始化这样能确定其地址
int p;
//相邻变量
printf("%p\n",&i);
printf("%p\n",&p);
C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第3张图片

//十六进制的c=12,因此两变量地址相差4,即一个int的字节大小。我们此时是在32位架构下编译,因此说明了,相邻变量在内存中的地址也是相邻的。

结果:

  • sizeof(&变量)(前面已试过,可行)

  • 数组的地址

  • 数组单元的地址

  • 相邻数组单元的地址

#include
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;
}
C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第4张图片

9.1.2 指针

如果能将变量地址取出,然后传递给一个函数,是否能通过这个变量的地址实现在函数中访问变量呢?

有没有感觉似曾相识:scanf("%d",&i);

思考:我们将一个地址传给scanf,它可以从其中取得我们输入的整数并放到变量i中。那么它是如何做到的呢?它是如何保存变量的地址的呢?什么样的变量可以接收取地址符得到的地址呢?

指针

概念:

  • 一个指针类型的变量就是保存地址的变量。

  • 通常用p表示指针(point)

int *p=&i;
//p是一个指针,指向一个int类型,并把i的地址交给p(也就是 p的值=i的地址
C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第5张图片
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

指针变量:

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

C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第6张图片

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

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

举例说明:

C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第7张图片
C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第8张图片

*运算符

  • 引入一个新运算符:*

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

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

#include 
    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.

C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第9张图片

*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;
}
C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第10张图片
  • 此时只需要传入两个地址即可完成交换,原理是相同的,但传入指针可以改变原始值。

定义函数返回多个值:

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

C语言_0309笔记_指针:定义/&和*/值的传递/函数返回多值/return和指针分工/常见错误_第11张图片

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

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

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

//两个整数作除法
#include
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);

你可能感兴趣的:(C语言_浙江大学_翁恺,c语言,数据结构,算法)