C语言基础——指针

本文详细探讨了C语言中的指针,包括基本概念、运算、与数组的关系、指针与字符串的交互,以及函数指针的使用。讲解了指针在数组、字符串和函数中的应用,并强调了指针运算中的注意事项,如指针加减法涉及的数据类型字节数。最后,文章总结了指针在C语言中的重要性和使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

指针的基本概念

指针:就是内存中某个字节地址编号
指针变量:用来存放地址变量
定义指针变量格式:指针所指向的数据类型 * 变量名
指针变量 8个字节的存储空间
没有初始化的指针里面放的也是垃圾值,这种没有指向指针我们成为野指针
        指针的初始化方式
  1、先定义再进行初始化
    int *p;
    p = &a;
  2、定义同时进行初始化
    int *pp = &a;

指针注意点

     1、指向是什么样类型的指针将来指针存放什么类型的变量的地址
     2、指针变量不可直接赋值一个整形常量,只能存放变量地址
     3、指针没有初始化不可以访问指针指向存储空间,里面是垃圾值,是一个没有指向指针,也就是说是一个野指针;如果你操作一个野指针就回导致系统崩溃
     4、指针的指向是可以改变的
     5、多个指针可以指向同一变量

     定义指针的目的:

     1、使用地址代替值拷贝 可以节省内存  2、共享数据

     2、指针是用来访问它指向存储空间中的数据的,但是指针变量里面存放的仅仅变量的首地址,如果没有数据类型,访问它所在指向存储空间的时候不知道取多少字节数据
     3、指针区分类型 是为了当通过指针访问对应的存储空间的时候,取相应字节的数据

指针与数组

    void test1(){
    //数组名不是一个指针
    int nums[] = {1,2,3,4,5};
    
    int *p = nums;
    //第一个不同点
    //   sizeof 计算变量所在存储空间的字节数
    int numsLength = sizeof(nums);
    printf("%d\n",numsLength);
    //指针变量占8个字节存储空间
    printf("%lu\n",sizeof(p));
    //sizeof(nums) != sizeof(p)
    //当一个数组赋值给一个指针变量,有些信息就丢失了,这个称为信息遗失,比如数组长度
    
    //第二个不同点
    // nums = &nums 数组名的地址就是数组的地址,所以可以使用指针代替数组类型作为函数参数
    printf("%p\n",nums);
    printf("%p\n",&nums);
    // p ! = &p  指针中存放地址与指针本身地址不同
    printf("%p\n",p);
    printf("%p\n",&p);
    //第三个不同点
    //数组名是不占用存储空间,当程序编译的时候所有出现数组名的地方都会被替换为数组的地址,所以不可以改变数组名的指向
    //指针变量的指向是可以改变的
    int num1s[] = {7,9};
    //    nums = num1s;
    p = num1s;
    printf("%d\n",p[1]);
    

}

指针运算

 void test(){
    //指针加法
    int nums[] = {1,2,3,4,5};
    
    int *p =  nums;
    //    printf("%p\n",p);
    //    printf("%p\n",p+1);
    //
    //    char *cp = nums;
    //    printf("%p\n",cp+1);
    //
    //    double *cd = nums;
    //    printf("%p\n",cd+1);
    指针 + 1 是加指针变量所指向的数据类型所占的字节数
    
    printf("%p\n",p);
    printf("%p\n",p-1);
    
    char *cp = nums;
    printf("%p\n",cp-1);
    
    double *cd = nums;
    printf("%p\n",cd-1);
    指针 - 1 是减去指针所指向的数据类型所占字节数
    /*
     指针可以+整形常量
     指针可以-整形常量
     */
    // p + cp; //两个指针不可以相加
    
    long len =  &nums[4] - p;
    printf("%ld\n",len);
    //两个地址之间有多个这种类型元素
    
    char names[] = "abc";
    
    long length =  &names[3] - names;
    
    printf("%ld\n",length);
    //指针是受限的无符号的长整形
    //指针的运算一般都是针对数组的
}
void test1(){
    int nums[] = {1,2,3};
    //nums++ == nums = nums + 1;//数组名是不占用存储空间的,它的指向不可以改变
    //(&nums[0])++;//地址常量不可以赋值
    int *p = nums;
    p++;//指针变量中的值是可以改变的
}

指针与字符串

void test(){
    //定义字符串变量的第一种方式
    char names[] = "ym";
    //使用数组定义的字符串是存放栈中的,它里面的字符是可以随便改的
    //第二种定义字符串变量的方式
    char *name1 = "ym";
    //使用指针定义的字符串是存放在常量区的,是不可以修改的
    names[0] = 'z';
    names[1] = 'j';
    printf("%s\n",names);
    *name1 = 'z';
    printf("%s\n",name1);
}
//    char *name = "abc";
//    scanf("%s",name);//错误的,因为此时name指向的是常量区
//    printf("%s\n",name);
//    scanf("%4s",name1);
//    %s遇到空格就结束了
//    printf("%s\n",name1);

void test2(){
    const char *name = "zj";
    定义指针变量时候,* 前面加 const 表示指针所指向这个存储区域是只读的
    //    *name = 'z';
    const int a = 10;
    //  a = 20;
    const 放在变量前面说明这个变量是只读的
    const int *p = &a;
    int b = 12;
    //    *p = 12;
    p = &b;
    printf("%d\n",*p);
    
    int * const pp = &b;
    //    pp = &a;
    const 放在 * 后面说明这个指针变量是不可以修改的
}

返回值为指针函数

注意点:不要在函数返回局部变量的指针,因为函数结束时候局部变量就被释放了
char * test(){
    char words[] = "today is good day";
    使用指针定义的字符,它是指向常量区,常量区的数据在程序启动的就被加载到内存了,直到程序退出才释放
    char *words =  "today is good day";
    return  words;
}
int main(int argc, const char * argv[]){
//    char *words = test();
//    printf("%s\n",words);
    
    int *num = test1();
    int b = 10;
    num = &b;
    printf("%d\n",*num);
    //告诉操作这个块存储空间我不用了
    free(num);
    //指针使用完毕要清空
    num = NULL;
    //printf("%d\n",*num);
 1 只要有一个malloc 就必须有一个对应的free
 2 当你没有释放对内存的存储空间不可以改变指针的指向

    return 0;
}

函数指针

函数指针:指向函数的指针,称为函数指针
void test(){
    //给函数指针进行赋值
    //调用函数时候必须是有小括号的
    //如果没有小括号是函数的地址
    printf("%p\n",test);
    //函数名就是函数的地址
    //    test = &test;
    pointer = test;//此处不带小括号
    //第一种方式
    pointer();
    //第二种方式
    (*pointer)();
    
//    1、只要定义指针变量必定是有名字
//    2、既然是指针就要有*号
//    3、若为函数指针就要把它括起来
//    4、把它将要指向的函数的左边拷贝其左边
//    5、把它将要指向的函数的右边拷贝其右边
    int (*sumPointer)(int num1,int num2);
    sumPointer = sum;
    int result = sumPointer(10,20);
    printf("result = %d\n",result);
}

总结

   指针:就是内存中字节的地址编号
   指针变量:用来存放地址变量,我们称为指针变量,只要知道变量的地址,就可以访问对应存储空间
    
   指针的定义格式:
         所指向的数据类型 * 指针变量名
   指针初始化的方式
         1、先定义指针变量,然后在进行初始化
         2、定义的同时进行初始化
   *作用:1、当用在变量定义的时候,他是一个类型说明符,说明定义的这个变量是一个指针变量
         2、在不是变量定义的时候,它是一个操作符,访问指针变量所指向的存储空间
   &作用:&它一个操作符,取出变量的地址
   当用作操作符的时候 * 与 &是一对反操作
    指针的作用:
        1、以传递地址代替数据拷贝
        2、在不同函数中共享数据
    指针的注意点:
        1、什么指向什么样类型的指针,只能存放什么样类型的变量地址
        2、指针不可以赋值一个整形常量
        3、不可以访问没有初始化的指针所指向存储空间,指针没有初始化它里面是一个垃圾值,这个指针是没有指向的,我们成为这样的指针为野指针
        4、指针的指向是可以改变的
        5、多个指针可以指向同一个变量
    指针的使用场景
        1、当一个函数中需要访问其他函数中的变量的时候,就需要使用指针
        2、当一个函数需要多个返回值的时候就要想到使用指针
    指针与函数
        1、指针作为函数参数传递它是地址传递
        2、局部变量的指针不可以作为函数返回值,因为局部变量在函数结束的时候就被销毁了。
 
    指针与数组
        1、数组像一个指针,数组访问其成员的方法与指针访问数组成员的方法相同
           我们可以使用访问指针所执行的存储空间的方式区访问数组中元素
           int array[] = {1,2,3};
           int *p = array;
           array[1] = *(array + 1) = p[1] = *(p+1) = *(p++)
        2、数组不是一个指针
           1、sizeof(array) != sizeof(p),把一个数组赋值一个指针变量,那么有些信息就丢失是了,我们成为信息遗失,比如数组所在存储空间
              sizeof(array)数组所占用存储空间的字节数
              sizeof(p) 指针变量所占字节数(8字节)
           2、array == &array  p != &p
              数组名就是数组的地址,指针的地址与指针所指向的地址不同
           3、数组的指向是不可以改变的,指针指向是可以改变的
 
   指针的运算:
        p + n  就相当于加上n个p所指向类型占用的存储空间的字节数
        p - n  就相当于减去n个p所指向类型占用的存储空间的字节数
        
        p1 - p2  它指的是p1 到 p2之间可以存放多少个指针所指向数据类型的数据
   指针与字符串
        1、定义字符串的两种方式
           1、使用字符数组,它是存放在栈中,字符串中的字符是可以任意修改的
               char name[] = "zbz";
           2、使用char * ,它是存储常量区,它是只读的
              const  char *name = "zbz";
        2、const作用
           1、在定义普通变量的时候,用在普通变量前,说明这个变量是只读的
           2、在定义指针变量的时候,用在*前面,说明指针所指向存储区域是只读的
           3、在定义指针变量的时候,用在*后面,说明指针变量的是只读的
        3、字符数组
            1、使用char类型二维数组,字符串是存放在栈中的
               char names[][10] = {"zbz","xmf"};
            2、使用char类型的指针数组,这个指针数组中存放是常量字符的地址,此时的字符串是一个常量是不可以修改的
               char * names[] = {"zbz","xmf"}
 
            3、指向数组的指针
               char (*p)[10] = names;
    函数指针:指向函数指针
    int sum(int a,int b) { return a + b;}
    1、既然是一个变量,那么就有名字
    2、若为指针变量就要有一个*
    3、若要指向函数就要把它去阔起来
    4、把它所要执行的函数的左边拷贝它左边
    5、把它所要指针向的函数的右边拷贝到它的右边
      int (*sumPointer)(int a,int b)
      sumPointer = sum
    
    6、函数的名字就是函数的地址 sum = &sum
       sumPointer();//通常使用这种
       (*sumPointer)();
 
  c语言中动态分配内存(堆内存)
     比如要给一个整形数分配存储空间
     int *p = malloc(sizeof(int));
     1、使用使用完毕需要自己回收内存
        free(p);
     2、在这个没有调用free函数之前必须有一个指针指向这块存储区域,否则这块存储区域就不会释放了,内存溢出
     3、当是用free释放p所指向存储空间的后,需要把p变量清空 p = NULL;
    
   多级指针
        int a = 10;
        int *p = &a;
   二级指针
        int **pp = &p;
        *pp == p;
        **pp == a;
   三级指针
         int ***ppp = &pp;
         *ppp == pp;
         **ppp == p;
         ***ppp == a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值