zoukankan      html  css  js  c++  java
  • C语言指针收藏

    指针是什么

    》》每一个内存单元只能同时存储一个数据,如何保证内存单元同时只能存储一个数据,可以使用编号的方式实现内存单元标记,此编号就是指针。

    》》指针是一个变量,指针是存放着一个数据的内存地址而不是数据本身的值,其是查找数据的另一种方式

    相关运算符

    【&】在变量中取地址

    【*】在地址中取变量

    测试小程序:

    #include<stdio.h>
    void main() {
        int i = 10;//定义一个变量,并赋初始值为10
        int *p = &i;//定义一个指针变量,并赋初始值为i的地址
        *p = 199;
        printf("%d=%d", *p,i);//输出199=199
        printf("---%d---", p);//得到变量i的地址
    }

    指针变量的类型

    》》指针类型:int *、float*、long*、double*、char*等等

    》》指针变量的类型需要与存储的数据类型相同

    》》确定类型可以方便指针变量确定存储数据的大小,为数据寻找到结束符,如int类型占四个字节、char占一个字节。也方便指针使用加1或减1操作,如int加减1会跳动4个字节,char加减1会跳动两个字节。

    指针的赋值

    int i=10;  int *p=&i;

    int *pp;

    pp=p;

    指针运算符:

    *p++

    等同于*(p++),运算优先级为从右到左,应该是先*p取值,然后地址移动一位,要区别与*(++p)。

     char *ch="0123";
     //printf("%c
    ",*ch++);//输出0 
     //printf("%c
    ",*(ch++));//输出0 
     printf("%c
    ",*(++ch));//输出1 

    指针变量作为函数参数

    #include<stdio.h>
    //int *a1=&b1;
    void fun(int *a1, int* a2) {
        
        *a1 = 100;
        int ii = 99;
        a2 = &ii;//让指针重新指向另外一个地址
        printf("得到的数据:%d,%d", *a1, *a2);//输出100,99
    }
    void main() {
        int b1 = 1, b2 = 2;
        fun(&b1, &b2);
        printf("调用函数后:%d,%d", b1, b2);//输出100,2
    }

    输出b2的结果并不是相同的值,是因为执行调用函数改变了实参指针变量的值,并不是改变了实参指针变量所指变量的值

    数组作为函数参数

    #include<stdio.h>
    void fun1(int *arr){
       arr[0]=10;
       arr[1]=11;
    }
    void fun2(int arr[]){
       arr[2]=100;
       arr[3]=110;
    }
    void main(){      
       //变量初始化 
       int i;
       int a[]={0,1,2,3,4,5,6};  
       //函数调用 
       fun1(a);
       fun2(a);   
       //打印
       for(i=0;i<sizeof(a)/sizeof(int);i++){
            printf("%d ",a[i]); //10 11 100 110 4 5 6
       }
    } 

    数组作为函数参数会自动退化为指针

    函数形参如果是数组,不管下标是多少都会自动转换为数组的首地址指针

     1 #include<stdio.h>
     2 
     3 void fun1(int *p){
     4     printf("%d",p[0]);//10
     5 }
     6 void fun2(int p[]){
     7     printf("%d",p[0]);//10
     8 } 
     9 
    10 void fun3(int p[100]){
    11     printf("%d",p[0]);//10
    12 }
    13 
    14 void fun4(char *p[]){
    15     printf("%s",p[0]);//dong
    16 } 
    17 
    18 void fun5(char **p){
    19     printf("%s",p[0]);//dong
    20 } 
    21  
    22 void main(){
    23    int ii[]={10,11,12};
    24    fun1(ii);
    25    fun2(ii);
    26    fun3(ii);
    27    char *ch[]={"dong","xiao"};
    28    fun4(ch);
    29    fun5(ch);
    30 } 

    一维数组指针变量

    数组名(如arr)代表元素的首地址,数组第一个元素的地址也是这个数组的首地址(如&arr[0])。

    数组指针中使用加减1将跳到下一个或者上一个数组元素地址,与使用 &arr[n+1] 基本相同。

    如果整数数组名为arr,运行int *p=arr,则*(p+3)、p[3]、*(arr+3)、arr[3]效果均是取出数组arr的第三个元素,在编译时arr[3]实际上是*(arr+3)处理的。

    #include<stdio.h>
    void main() {
        int arr[] = { 5,4,3,2,0 };
        int *p = arr;
        int *pp = &arr[0];
        printf("%d", *(p+3));//输出2
    }

    函数数组参数

    #include<stdio.h>
    //等价于void fun(char a1[]) {
    void fun(char *a1) {
        *(a1 + 2) = 'c';//改变第二个值的内容
    }
    void main() {
        char b1[] = { "123456789" };
        fun(b1);
        printf("调用函数后:%s", b1);//输出: 12c456789
    }

    二维数组指针变量

    #include<stdio.h>
    void main() {
        int a1[][3] = { {10,11,12},{100,110,120} };
        int a[][3] = { 10,11,12,100,110,120 };
        printf("地址:%d==%d==%d==%d", a[0], &a[0][0],*(a+0),a+0);//输出地址
        printf("%d===%d==%d", a[0][1], *(*(a + 0)+1),*(a[0]+1));//得到值
    }

    指针引用字符串

    字符串常量【char *ch = "dong xiao dong";】表示其指向地址的内容不可变,但指向的地址是可变的;

    字符串变量【char ch[] = "dong xiao dong";】其指向地址的内容可变。

    #include<stdio.h>
    void main() {
        //char *ch = "dong xiao dong"; //字符串常量,不可变 
        char ch[] = "dong xiao dong";  //字符数组,可变
        ch[2] = '2';//字符串常量运行这条将报错
        printf("%s
    ", ch);
    }

    可变格式的输出函数:

    #include<stdio.h>
    void main() {
        char *ch = "dong xiao %d
    ";
        printf(ch, 10);
        ch = "xiaoxiao%d
    ";
        printf(ch, 10);
        char chh[] = "dongdong %d
    ";
        printf(ch, 100);
    }

    指向函数的指针

    【int(*p)(int, int);//定义一个函数指针变量p】,第一个int表示返回值类型,第二个int和第三个int表示函数的参数类型。注意*p两侧的括号不能省略,表示p先与*结合,是指针变量,然后再于后面的()结合,()表示是函数,即该指针变量不是指向一般的变量,而是指向函数。如果写成“int * p(int,int);”,由于()优先级高于*,它相当于“int *(p(int,int))”,就成了声明一个p函数,并且这个函数的返回值是指向整型变量的指针。

    返回值为int

    #include<stdio.h>
    void main() {
        int minto(int a, int b);//函数声明
        int(*p)(int, int);//定义一个函数指针变量p
        p = minto;//函数指针指向函数minto首地址
        int cc = (*p)(11, 55);//调用函数
        printf("Min===%d", cc);
    }
    
    int minto(int a, int b) {
        if(a > b) return b;
        else return a;
    }

    无返回值:

    #include<stdio.h>
    void main() {
        void fun(int a);//函数声明
        void (*p)(int);//定义一个函数指针变量p
        p = fun;//函数指针指向函数fun首地址
        (*p)(11);//调用函数
    }
    void fun(int a) {
        printf("%d
    ", a);  
    }

    指向函数指针作为函数的参数

    #include<stdio.h>
    void main() {
        int fun(int(*addpp)(int, int), int x, int y);//函数声明
        int add(int i, int j);
    
        int ii=fun(add, 11, 12);//传递函数名和参数即可
        printf("输出相加的值为:%d", ii);
      }
    
    //int (*addpp)(int,int);addpp=add;
    int fun(int (*addpp)(int,int),int x,int y){
        int cc = (*addpp)(x, y);
        return cc;
    }
    
    int add(int i, int j) {
        return i + j;
    }

    返回指针的函数

    #include<stdio.h>
    void main() {
        int* add(int i, int j);
        int *p = add(10, 4);
        printf("输出相加的值为:%d", *p);
      }
    
    int* add(int i, int j) {
        int aa = i + j;
        return &aa;//返回地址
    }

    指针数组

    一个数组其全部元素都存放着指针,就是指针数组【int * p[5];】

    #include<stdio.h>
    void main() {
        //指针数组
        char * p[] = { "dong1","xiao2","dong3","dong4" };
        printf("%s
    ", p[2]);
      }

    进阶版

    #include<stdio.h>
    void main() {
        //指针数组(字符串)
        char * p[] = { "dong1","xiao2","dong3","dong4" };
        char **pp;
        pp = p;
        printf("%s
    ", *(pp+1));//转换一次就可以拿到对应字符串的首地址通过%s打印
    
        //指针数组(整数)
        int a[5]= {10,11,12,13 };
        int * ip[] = { &a[0],&a[1],&a[2],&a[3],&a[4]};
        int **ppp = ip;
        printf("%d
    ", *(*ppp+1));//转换第一次得到存储的指针,再次转换得到值
      }

    void类型指针

    void a;//定义一个无类型变量,错误,不能确定分配的内存大小
    void *a;//定义一个无类型指针,可行,指针类型都是4个字节(32位,64位为8个字节)

    void *p;表示指针变量p不指向一个确定的类型数据,它的作用仅仅是用来存放一个地址。

    可以将任意类型的指针直接给void指针赋值,但是如果需要将void指针的赋值给其他类型的指针,则需要进行强制类型转换

    #include<stdio.h>
    
    void fun1(void *i){
      int *p=(int *)i;//强制类型转换 
      *p=100;
    }
    
    void main(){
      int ii=10;
      fun1(&ii);
      printf("%d",ii);//输出100 
    } 

    错误示范

    1、

    int *p=10; //等同于:int *p; p=10;

    分析:非法操作,内存地址不能用户自定义。10相当于一个内存地址,该内存地址的值不确定且也不明确该地址是否可以直接访问,正确的应该是使用【&变量名】得到内存地址。

    2、

    int f = 12.3;
    int *p;
    *p = &f;  //错误1
    int ff = &f; //错误2

    分析:指针(地址)必须赋值给指针变量

  • 相关阅读:
    小数据池,bytes
    不会的知识总结:
    nginx低版本不支持pathinfo模式,thinkphp针对此问题的解决办法
    备份了一个nginx的虚拟主机配置文件报错
    centos修改ssh端口
    CentOS安装配置Git服务器(gitosis)
    干货CentOS6.5_Nginx1.40_Php5.57_MySQL5.5.35编译安装全记录
    编译升级php
    php源代码安装常见错误与解决办法分享
    兼容IE,Firefox,Opera等浏览器的添加到收藏夹js代码实现
  • 原文地址:https://www.cnblogs.com/dongxiaodong/p/10743246.html
Copyright © 2011-2022 走看看