# 一. Tutorials

# 1. NULL指针

  • 对NULL指针进行解引用操作是非法的,因此需要判断该指针是否为NULL;
  • 一种更为安全的策略是让函数返回两个独立的值(可以是包含多个元素的结构体):首先是状态值,用于提示查找是否成功。其次是个指针,当状态值提示查找成功时,它所指向的就是查找到的元素。

# 2. 函数声明与函数原型

  • 在main前声明函数;
  • 在main后声明函数,但需要在main前使用函数原型。

# 3. 函数可变参数列表

对于可变参数列表所使用的宏,存在如下两个基本的限制。这两个限制导致的一个直接结果是,一个值的类型无法简单地通过检查它的位模式来判断。

  • 这些宏无法判断实际存在的参数的数量。
  • 这些宏无法判断每个参数的类型。 要绕开这两个显示,就必须使用命名参数。
#include <stdio.h>
#include <stdarg.h>

/*
    可变参数列表需要使用类型va_list和3个宏——va_start、va_arg、va_end
    1. va_start(va_list, named_arg)
       第1个参数为va_list类型数据
       第2个参数为省略号前最后一个命名参数
    2. va_arg(va_list, type)
       第1个参数为va_list类型数据
       第2个参数为数据类型
       该宏返回指向的参数列表中的参数,每调用一次,其指向后移
    3. va_end(var_list)
       当访问完最后一个可变参数后,需要调用va_end
*/

float average(int num, ...);

int main()
{
    float res = average(2, 3, 4, 5);
    printf("%f", res); // 3.500000
    
    return 0;
}

float average(int num, ...)
{
    va_list var_arg;
    int count;
    float sum = 0.0;

    va_start(var_arg, num);
    for(count=0; count<num; count+=1)
    {
        sum += va_arg(var_arg, int);
    }
    va_end(var_arg);

    return sum / num;
}

# 4. 存根

对于空函数体的函数定义,可以保证程序逻辑上的完整性,该函数可以称位存根。

# 5. 数组名

数组名的类型是常量指针,但数组和指针又是不同的。例如,数组剧有确定数量的元素,二指针知识一个标量值。编译器用数组名来记住这些属性。只有当数组名再表达式中使用时,编译器才会为它产生一个指针常量。

以下操作是等效的

// 1
int a[10];
int *c;
c = &a[0];
// 2
c = a

# 6. 下标引用

以下操作是等效的

array[sub]
*(array + sub)