C语言:指针(第四天)

C语言:指针(第四天)

main 函数原型

定义:main函数有多种定义格式,main函数也是函数,函数相关的结论对main函数也有效(也可以定义main函数的函数指针)

main函数的完整写法:

int main(int argc,char *argv[]){}
int main(int argc,char **argv){}

扩展写法:

int main(){}
int main(void){}
void main(){}
void main(void){}
...

说明:

  1. argc,argv是形参,他们俩可以修改

  2. main函数的扩展写法有些编译器不支持,编译报警告

  3. argc和argv的常规写法:

    • argc:存储了参数的个数
    • argv:存储了所有参数的字符串形式
    #include <stdio.h>
    int main(int argc, char *argv[])
    {
        printf("argc=%d\n", argc);
        int i = 1;
        for (; i < argc; i++)
        {
            printf("%s,%s\n", argv[i], *(argv + i)); // 下标法和指针法
        }
        return 0;
    }
    

在这里插入图片描述

  1. main函数是系统通过函数指针的回调调用的

    int add(int a, int b) { return a + b; }
    int jisuan(int a, int b, int (*ADD)(int, int))
    {
        printf("开始计算:\n");
        // 执行函数add
        ADD(a, b);
    }
    int main()
    {
        int a = 5, b = 3;
        jisuan(a, b, add);
    }
    

常量指针与指针常量

常量:分为字面量和只读常量,字面量就是我们平时直接操作的量:printf(“%d\n”,12);/printf(“%s\n”,hello);只读常量使用关键字const修饰,凡是被这个关键字修饰的变量,一旦赋值,值就不能改变。

语法:

// 字面量
printf("%d\n",12);

// 只读常量
const int a = 10;
a = 21;// 编译错误,因为此时这个变量是只读常量,所以不能更改其值

常量指针

定义:常量的指针,本质是一个指针,指针指向的数据不能改变。

定义格式:

const 数据类型 *变量名

举例:

const int *p;// p就是常量指针

结论

  1. 常量指针指向的数据不能被改变。(不能解引用间接修改数据)
  2. 常量指针的地址可以改变。(指向是可以改变的)

应用场景:一般作为形式参数,实际参数需要给一个常量。

void foreach(const int *array,const int len)
{
    ...
}

案例:

#include <stdio.h>

int main()
{
    // 定义变量
    int a = 10;
    
    //定义常量指针
    const int *p = &a;
    
    // *p = 100;// 编译报错,常量的值不能被改变
    printf("%d\n",*p);
    
    // 定义变量
    int b = 20;
    p = &b; // 编译通过,常量的地址可以被改变
    printf("%d\n",*p);
    
    return 0;
}

指针常量

定义:指针的常量,指针的指向不能改变

定义格式:

数据类型* const 变量名;

举例:

int* const p;// 指针常量

结论:

  1. 指针常量的指向不能改变。(不能给指针变量重新赋地址值)
  2. 指针常量指向的数据可以改变。

注意:指针常量在定义时就要赋值;不能先定义后赋值,否则编译报错

案例:

#include <stdio.h>

int main()
{
    // 定义变量
    int a = 10;
    
    //定义常量指针
    int* const p = &a;
    
	*p = 100;// 编译通过,常量的值可以被改变
    printf("%d\n",*p);// 100
    
    // 定义变量
    int b = 20;
    // p = &b; // 编译报错,常量的地址不可被改变
    printf("%d\n",*p);// 100
    
    return 0;
}

常量指针常量

定义语法:

const 数据类型* const 变量名;

举例:

const int* const p;

作用:p的指向不能被改变(地址不可更改),p指向的数据不能改变(地址对应的数据不可更改)

动态内存分配

我们要想实现动态内存分配,就需要学习标准C提供的函数库(API):

  1. 函数所属的库文件
  2. 函数的原型-函数的声明
    • 函数名
    • 形参
    • 返回值类型
  3. 函数的功能

注意:内存分配函数在申请内存时,建议用多少申请多少,可以有少量的预留量但不能越界访问,虽然编译和运行无报错,但是数据不安全(野指针)

常用函数

malloc
  • 头文件:#include <stdio.h>

  • 函数功能:C库函数void *malloc(size_t size);分配所需的内存空间,并返回一个指向它的指针。

  • 函数原型:

    • 函数名:malloc

    • 形式参数:size_t size:需要申请的内存块的大小,以字节为单位。本质上是一个unsigned long int

    • 返回值类型:void*(万能指针):该函数返回一个指针,指向已分配大小的内存,如果请求失败,返回NULL(0x000000000000对应的一块不可访问的区域)

    • 举例:

      int* p =(int*)malloc(sizeof(int));
      // 清零,清除内存中的随机值
      bzero(p,sizeof(int));
      // 使用空间...
      // 释放空间
      free(p);
      
    • 说明:

      • malloc函数分配的内存没有默认值,内存中的数据是随机值(大概率是0),使用前需要借助于bzero()清零。
      • malloc函数申请的内存空间连续

calloc

  • 头文件:#include <stdlib,h>\

  • 函数功能:C库函数void* calloc(size_t nitems,size_t size)分配所需的内存空间,并返回一个指向它的指针。

    malloc和calloc之间的区别:malloc不会设置内存为零,需要使用bzero()清零,而calloc会设置内存为零。

  • 函数原型:

    • 函数名:calloc

    • 形式参数:

      • size_t nitems:申请多少个
      • size_t size:一个占几个内存单元(1个内存单元=1个字节)
    • 返回值类型:void*:该函数返回一个指针,指向已分配大小的内存,如果请求失败,返回NULL

    • 举例:

      int* p =(int*)calloc(1,sizeof(int));
      free(p);
      
    • 说明:

      • calloc函数分配的内存有默认值,每个内存单元都是0
      • calloc函数申请的内存空间连续
      • calloc大多时候为数组中的元素申请内存
    • 案例:

      /**
       * 需求:转存栈中数组中的数据
       */
      
      
      #include <stdio.h>
      #include <stdlib.h>
      
      int main()
      {
          // 在栈区创建一个数组
          int arr[3] = {11,22,33};
          
          // 在堆区申请空间
          int *p = (int*)calloc(3,sizeof(int));
          
          // 转存
          for(int i = 0;i < 3;i++)
          {
              p[i] = arr[i];
          }
          
          // 遍历堆中数据
          for(int i = 0;i < 3;i++)
          {
              printf("%-4d\n",p[i]);
          }
          printf("\n");
          // 在堆中申请空间,使用完毕释放空间
          free(p);
          p = NULL;
          printf("p=%p\n",p);
          
          return 0;
      }
      
realloc
  • 头文件: #include <stdlib.h>

  • 函数功能:尝试重新调整之前调用malloc或calloc所分配的ptr所指向的内存块的大小。

  • 函数原型: void *realloc(void *ptr,size_t size)

    • 函数名:realloc

    • 形式参数:

      • void *ptr:是malloc或者calloc的返回值

      • size_t size:重新分配后的内存大小

    • 返回值:void*:该函数返回一个指针,指向已分配大小的内存。如果请求失败,返回NULL。

  • 案例:

    int *p = (int *)malloc(4);
    int *w = (int *)realloc(p, 20);
    // int *q = (int*)realloc(p,0); // 等效于free(p)
    
  • 说明:

  1. realloc以原来malloc返回的内存地址开始,分配总共20个字节的内存空间
  2. 如果原来的内存空间后有20个连续空间,就扩容20-4 =16个内存单元,返回原来旧的内存首地址。
  3. 如果原来的内存空间后不够20个连续内存空间,就重新找一个内存地址开始,申请20个内存单元。并将原来的数据拷贝到新的内存中,回收旧的内存单元,并返回新的内存首地址。
free
  • 头文件: #include <stdlib.h>

  • 函数功能:释放之前调用 malloc、calloc、realloc所分配的内存空间,是访问完记得使用NULL置空。

  • 函数原型: void free(void *ptr)

    • 函数名:free

    • 形式参数:

      • void *ptr:calloc,malloc.realloc的返回值
    • 返回值类型:void:没有返回值

  • 注意:

  1. 堆内存中的指针才需要回收,栈中系统会自动回收
  2. 堆内存不能重复回收,运行会报错

说明:

  1. 堆的内存空间相比较栈要大很多

  2. 内存分配函数返回的指针变量可以参与运算(只读),但不能被修改(p++或者p+=i 是错误的)

附表

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值