05 C Function

函数

函数应用

交换变量函数

//错解1:只交换形参的值
void swap(int x, int y)
{
    int z;
    z = x;  x = y;   y = z;
}
//错解2:*p无确定指向
void swap(int* p1, int* p2)
{
    int *p;
    *p = *p1; *p1 = *p2; *p2 = *p;
}
//错解3:只交换形参指向
void swap(int *p1, int *p2)
{
    int *p;
    p = p1; p1 = p2; p2 = p;
}
//正解:通过形参指针改变实参变量的值
void swap(int* p1, int* p2)
{
    int z;
      z = *p1;
    *p1 = *p2;
    *p2 = z;
}

转化二进制函数(递归)

#include <stdio.h>
void to_binary(unsigned long n)
{
    int r = n % 2;
    if (n >= 2)
        to_binary(n / 2);
     putchar(r == 0 ? '0' : '1');
    return;
}
int main(void)
{
    unsigned long number;
    printf("Enter an integer (q to quit):\n");
    while (scanf("%lu", &number) == 1)
    {
        printf("Binary equivalent: ");
        to_binary(number);
        printf("\nEnter an integer (q to quit):\n");
    }
    printf("Done.\n");
    return 0;
}

变量

  1. 局部变量与全局变量

    1. 作用域 能够被直接访问的代码范围(空间角度)

      生命期 在内存中具有相应的内存空间的时间范围(时间角度)

    2. 局部变量

      • 作用域:从定义处到函数(或复合语句)结束。局部变量只能在这个范围内被直接访问

      • 生命期:依赖于存储类别,可能是从函数调用开始到结束,也可能是从程序执行开始到结束

    3. 全局变量

      • 作用域:从定义处到源文件结束。全局变量可以在这个可能包含多个函数的范围内被直接访问
      • 生命期:从程序执行开始到结束
    4. 变量定义和声明

      • 把建立存储空间的变量声明称为定义,而把不需要建立存储空间的变量声明称为声明
      • 外部变量是对变量的声明,除此以外,其它的变量声明都是定义
  2. 变量的存储类别 StorageClass Type Name;

    1. 自动变量(auto)
      • 必须是局部变量,若未显式声明存储类别,就为自动变量
      • 作用域:从定义处到函数(或复合语句)结束
      • 生命期:从函数调用(或复合语句执行)开始到结束。函数调用开始时,系统会给自动变量分配存储空间,调用结束时就自动释放空间
    2. 外部变量(extern)
      • 外部变量可以是局部或全局变量。外部变量并不定义一个新的变量,而是扩展一个全局变量的作用域
      • 作用域:对于局部变量,从定义处到函数(或复合语句)结束;对于全局变量,从定义处到文件结束。
      • 生命期:从程序执行开始到结束
      • 在函数定义前也加 extern 能够将函数的作用域扩展到其它文件中,其它文件可以调用该函数。若未显式声明为 extern ,则默认为外部函数
    3. 静态变量(static)
      • 必须是局部变量
      • 作用域:从定义处到函数(或复合语句)结束
      • 生命期:从程序执行开始到结束。在函数调用结束后不释放静态变量的内存空间,在下一次再调用该函数时,该静态变量的值就是上一次函数调用结束时的值
      • 在全局变量或者函数定义前加 static ,并不定义静态存储,而是将全局变量或函数的作用域限制在本文件中,其它文件即使使用extern外部声明也无法访问或调用如static int A; static void func();
    4. 寄存器变量
      • 必须是局部变量
      • 寄存器变量存放在 CPU 寄存器中
      • 作用域和生命期与 auto 变量相同

程序的内存布局

  1. 代码段 text segment 用于存储可执行指令
  2. 数据段 data segments 用于存储全局变量和静态局部变量。其中,未初始化数据段中的变量将被初始化为0
  3. 堆 heap 用于动态内存分配,空间从低地址往高增长
  4. 栈 stack 用于存储函数栈帧,空间从高地址往低增长
  • 程序开始执行时给 全局变量和静态局部变量 分配内存空间,默认初始值为0。程序执行完毕时释放空间
  • 函数调用开始时给 自动局部变量(包括形参) 分配内存空间,初始值为随机值(内存遗留垃圾)。函数调用结束时释放空间

动态内存分配

中分配指定大小内存空间,包含头文件#include<stdlib.h>

malloc函数

void *malloc(unsigned size);

在内存的堆中分配一个长度为size的连续内存空间。返回所分配空间的首地址(指针类型)。若未能成功执行(例如内存空间不足),则返回空指针(NULL)

int *p;
p = (int *) malloc(100);//应坚持使用强制类型转换
*p = 1;
printf("%d\n", *p); 

calloc函数

void *calloc(unsigned n,unsigned size);

分配 n 个长度为 size 的连续内存空间,返回值与 malloc 一样

int* p;
p = (int *) calloc(5, 20);
*p = 1;
printf("%d\n", *p);

free函数

void free(void *p);

动态分配的内存只能增加,必须进行清理

释放指针p所指向的内存空间,使这部分空间能重新被分配使用

int* p;
p = (int *) malloc(100);
*p = 1;
printf("%d\n", *p);
free(p);
p = (int *) calloc(5, 20);
*p = 2;
free(p);

realloc函数

void *realloc(void *p,unsigned size);

若 p 所指向的内存空间是通过 malloc 函数或 calloc 函数分配的,那么将这个内存空间的大小改为 size,返回值与 malloc 一样

int *p, *q;
p = (int *) malloc(100);
*p = 1;
q = (int *) realloc(p, 20);
printf("%p, %p, %d\n", p, q, *q);
free(p); 

函数指针

指向函数的起始地址

Type (*Name)([ParameterList]);

例:定义类型为int (*)(int, int)的指针变量 p ,指向一个函数,这个函数的类型为整型且有两个整型形参

#include <stdio.h>
int add(int a, int b)
{return a + b;}
int main()
{ 
    int (*p)(int, int);
    int i;
    p = add; // right
    //p = add(1, 2); wrong
    i = (*p)(1, 2);//right
    i = p(1, 2);//right
    printf("%d\n", i);
    return 0;
}

函数指针算术运算无意义,如p+n, p++

posted @ 2025-04-11 16:30  YamadaRyou  阅读(11)  评论(0)    收藏  举报