C语言学习指针

---恢复内容开始---

一.运算符 &
• scanf(“%d”, &i);里的&
• 获得变量的地址,它的操作数必须是变量
• int i; printf(“%x”,&i);
• 地址的⼤大小是否与int相同取决于编译器
• int i; printf(“%p”,&i);

• &不能对没有地址的取地址
• &(a+b)?
• &(a++)?
• &(++a)?

二.指针初识
就是保存地址的变量
int i;
int* p = &i;
int* p,q;
int *p,q;

指针变量

• 变量的值是内存的地址
• 普通变量的值是实际的值
• 指针变量的值是具有实际值的变量的地址 

试试这些&
• 变量的地址
• 相邻的变量的地址
• &的结果的sizeof
• 数组的地址
• 数组单元的地址
• 相邻的数组单元的地址

#include <stdio.h>
int main()
{
 int data=100;
 int * pd;
 pd = &data;
// int *pd =&data;   指针变量定义另一种方式;声明与初始化一步完成
 printf("data=%d\n",data); //变量的直接访问
 printf("data=%d\n",*pd); //变量的直接访问
 
printf("%lu\n",sizeof(int));
 printf("%lu\n",sizeof(&data));//在32位下,int和地址都是4个字节
 
printf("address=%d\n",&data); //变量的地址输出
 printf("address=%d\n",pd);  //指针变量的输出
 
 return 0;
}

 取数组的地址

#include <stdio.h>
int main(void)
{
    int i=0;
    int p;
    
    int  a[10];
//    printf("%p\n",&i);
//    printf("%p",&p);  
    printf("%p\n",&a);
    printf("%p\n",a);
    printf("%p\n",&a[0]);
    printf("%p\n",&a[1]);

    return 0;
}

 我们可以看到,&a==a==&a[0];而int数组中的每个元素的地址永远是相差4,也就是一个sizeof(int)的大小

三.作为参数的指针
• void f(int *p);
• 在被调用的时候得到了某个变量的地址:
• int i=0; f(&i);
• 在函数⾥里面可以通过这个指针访问外面的这个i

#include <stdio.h>
int main(void)
{
 int i=6;
 int p;
    printf("&i=%p\n",&i);
    f(&i);
   
    return 0;

void f(int *p)
{
 printf("p=%p\n",p);//这样就可以访问函数外面的变量
}

四.访问那个地址上的变量*

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

• 可以做右值也可以做左值
• int k = *p;
• *p = k+1;

五.*左值之所以叫左值

• 是因为出现在赋值号左边的不是变量,而是值,是表达式计算的结果:

• a[0] = 2;
• *p = 3;
• 是特殊的值,所以叫做左值

指针应用场景一
• 交换两个变量的值

 

 指针应用场景二
• 函数返回多个值,某些值就只能通过指针返回
• 传入的参数实际上是需要保存带回的结果的变量

#include <stdio.h>
void minmax(int a[],int len, int *max, int *min);
int main(void)
{
    int a[]={1,2,3,4,56,6,7,8,9,12};
    int min,max;
    minmax(a,sizeof(a)/sizeof(a[0]),&max,&min);
    printf("min=%d,max=%d",min,max);
}

void minmax(int a[],int len, int *max, int *min)  //int a[] 就是指针,改成int *a也可以编译成功
{
    int i;
    *min = *max =a[0];
    for (i=1;i<len;i++){
        if (a[i]< *min){
            *min =a[i];
        }
        if (a[i]>*max){
            *max = a[i]; 
        }
    }
}

 指针应用场景二b

• 函数返回运算的状态,结果通过指针返回

• 常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错:

• -1或0(在文件操作会看到大量的例子)

• 但是当任何数值都是有效的可能结果时,就得分开返回了

• 后续的语言(C++,Java)采用了异常机制来解决这个问题

#include <stdio.h>  //函数返回运算的状态,结果通过指针返回 
int divide(int a,int b,int *result);
int main()
{
    int a=5;
    int b=2;
    int c;
    if (divide(a,b,&c) ){
        printf("%d/%d=%d\n",a,b,c);
    }
    return 0;
 } 
 
int divide(int a,int b,int *result)
{
    int ret =1 ;
    if( b==0 ) ret=0;
    else{
        *result= a/b;
    }
    return ret;
}

 指针最常见的错误
• 定义了指针变量,还没有指向任何变量,就开始使⽤指针

传⼊入函数的数组成了什么

 • 函数参数表中的数组实际上是指针
• sizeof(a) == sizeof(int*)
• 但是可以用数组的运算符[]进行运算

六.数组参数
• 以下四种函数原型是等价的:
• int sum(int *ar, int n);
• int sum(int *, int);
• int sum(int ar[], int n);
• int sum(int [], int);

七.数组变量是特殊的指针
• 数组变量本⾝身表达地址,所以
• int a[10]; int*p=a; // ⽆无需⽤用&取地址
• 但是数组的单元表达的是变量,需要⽤用&取地址
• a == &a[0]
• []运算符可以对数组做,也可以对指针做:
• p[0] <==> a[0]
• *运算符可以对指针做,也可以对数组做:
• *a = 25;
• 数组变量是const的指针,所以不能被赋值
• int a[] <==> int * const a=… .  

 八.指针与const (C99 only)

指针是const
• 表示一旦得到了某个变量的地址,不能再指向其他变量

• int * const q = &i; //  q 是 const

• *q = 26; // OK
• q++; // ERROR

所指是const
• 表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)

• const int *p = &i;
• *p = 26; // ERROR! (*p) 是 const
• i = 26; //OK
• p = &j; //OK

int i;
const int* p1 = &i; //指针所指不能修改
int const* p2 = &i;//指针所指不能修改
int *const p3 = &i; //指针不可修改
判断哪个被const了的标志是const在*的前面还是后面

 转换
• 总是可以把⼀一个非const的值转换成const的
void f(const int* x);
int a = 15;
f(&a); // ok
const int b = a;
!
f(&b); // ok
b = a + 1; // Error!
• 当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改

const数组
• const int a[] = {1,2,3,4,5,6,};
• 数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int

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

保护数组值
• 因为把数组传⼊入函数时传递的是地址,所以那个函数内部可以修改数组的值

• 为了保护数组不被函数破坏,可以设置参数为const
• int sum(const int a[], int length);

---恢复内容结束---

猜你喜欢

转载自www.cnblogs.com/guoweilf/p/11480277.html