c语言基础(九)---知识点补充

一.#include用法

#include叫做文件包含命令,用来引入对应的头文件(.h文件)。#include 也是C语言预处理命令的一种。

include的处理过程很简单,就是将头文件的内容插入到该命令所在的位置,从而把头文件和当前源文件连接成一个源文件,这与复制粘贴的效果相同。

include 的用法有两种,如下所示:

#include <stdHeader.h>
#include "myHeader.h"

使用尖括号< >和双引号" "的区别在于头文件的搜索路径不同:

  • 使用尖括号< >,编译器会到系统路径下查找头文件;
  • 而使用双引号" ",编译器首先在当前目录下查找头文件,如果没有找到,再到系统路径下查找。

也就是说,使用双引号比使用尖括号多了一个查找路径,它的功能更为强大。

前面我们一直使用尖括号来引入标准头文件,现在我们也可以使用双引号了,如下所示:

#include "stdio.h"
#include "stdlib.h"

stdio.h 和 stdlib.h 都是标准头文件,它们存放于系统路径下,所以使用尖括号和双引号都能够成功引入;而我们自己编写的头文件,一般存放于当前项目的路径下,所以不能使用尖括号,只能使用双引号。

当然,你也可以把当前项目所在的目录添加到系统路径,这样就可以使用尖括号了,但是一般没人这么做,纯粹多此一举,费力不讨好。

在以后的编程中,大家既可以使用尖括号来引入标准头文件,也可以使用双引号来引入标准头文件;不过,我个人的习惯是使用尖括号来引入标准头文件,使用双引号来引入自定义头文件(自己编写的头文件),这样一眼就能看出头文件的区别。

关于 #include 用法的注意事项:

  • 一个 #include 命令只能包含一个头文件,多个头文件需要多个 #include 命令。
  • 同一个头文件可以被多次引入,多次引入的效果和一次引入的效果相同,因为头文件在代码层面有防止重复引入的机制
  • 文件包含允许嵌套,也就是说在一个被包含的文件中又可以包含另一个文件。

#include 用法举例

我们早就学会使用 #include 引入标准头文件了,但是如何使用 #include 引入自定义的头文件呢?下面我们就通过一个例子来简单地演示一下。

本例中需要创建三个文件,分别是 main.c、my.c 和 my.h,如下图所示:
在这里插入图片描述
my.c 所包含的代码:

//计算从m加到n的和
int sum(int m, int n) {
    int i, sum = 0;
    for (i = m; i <= n; i++) {
        sum += i;
    }
    return sum;
}

my.h 所包含的代码:

//声明函数
int sum(int m, int n);

main.c 所包含的代码:

#include <stdio.h>
#include "my.h"
int main() {
    printf("%d\n", sum(1, 100));
    return 0;
}

我们在 my.c 中定义了 sum() 函数,在 my.h 中声明了 sum() 函数,这可能与很多初学者的认知发生了冲突:函数不是在头文件中定义的吗?为什么头文件中只有声明?

「在头文件中定义定义函数和全局变量」这种认知是原则性的错误!不管是标准头文件,还是自定义头文件,都只能包含变量和函数的声明,不能包含定义,否则在多次引入时会引起重复定义错误。

二.内存分区

c语言有五大内存分区,分别是栈,堆,全局区,常量区,代码区。

:在需要的时候由编译器(系统)自动分配,在不需要的时候会由系统自动回收的存储区,内存由系统管理,函数中定义的变量存储在栈中,当调用函数的时候函数中定义的变量会被加到栈中,当函数离开的时候,被添加的变量会从栈中移除,栈在最高的地址上,所以添加的变量地址会逐渐变小,里面的内容可读可写。

:是一块动态内存,由程序猿自己申请自己释放的内存空间,其内存由程序猿自己管理,当程序运行时候动态分配给变量,它可以长时间存在,所以,申请一个堆内存就必须有释放的过程,同时指向堆内存的指针不能改变,否则这个堆内存永远都得不到释放,除非程序崩溃或者运行结束导致系统回收程序所在的内存,这样就很容易造成内存泄漏(是指程序运行期间,程序结束后程序所占用的内存就释放了),它是可读可写的。

全局区(globals):定义在函数外边的全局变量和静态变量就放在这个这里,这里的变量在程序已启动就被创建,你可以自由的更改他们,所以是由系统管理的可读可写的内存。

常量区(constants):常量在系统一运行被创建,常量区的内存是只读的,如常量字符串就放在这个区。你可以读他们,但是不可以修改他们,内存由系统管理。

代码区(code):代码区是只读的,该区域是用来存放程序的代码的,内存由系统管理。

注意:这里的栈不是数据结构中所说的栈

动态存储空间(堆)的使用(了解):

  • 它的内存由程序猿管理
  • 使用:
  1. 导入stdlib.h
  2. int *pi = malloc(sizeof(int) malloc向操作系统申请堆中的一块空间,如果操作系统分配成功,就会返回存储空间的地址,否则返回null
  3. free(void *p):告诉操作系统这块存储空间不再使用了,并不会立即回收,对空指针无效,即不能多次释放同一个指针指针的堆内存空间
  4. 有malloc就有free,不然容易造成内存泄漏。
  5. 不要改变指向堆内存的指针
  • 使用场景:面试考数据结构要用到堆,如实现队列
  • 多种申请堆内存的函数,如:malloc,calloc
三.constant常量

有时候我们希望定义这样一种变量,它的值不能被改变,在整个作用域中都保持固定。例如,用一个变量来表示班级的最大人数,或者表示缓冲区的大小。为了满足这一要求,可以使用const关键字对变量加以限定:

const int MaxNum = 100;  //班级的最大人数
这样 MaxNum 的值就不能被修改了,任何对 MaxNum 赋值的行为都将引发错误:
MaxNum = 90;  //错误,试图向 const 变量写入数据


我们经常将 const 变量称为常量(Constant)。创建常量的格式通常为:
const type name = value;
const 和 type 都是用来修饰变量的,它们的位置可以互换,也就是将 type 放在 const 前面:
type const name = value;
但我们通常采用第一种方式,不采用第二种方式。另外建议将常量名的首字母大写,以提醒程序员这是个常量。

由于常量一旦被创建后其值就不能再改变,所以常量必须在定义的同时赋值(初始化),后面的任何赋值行为都将引发错误。一如既往,初始化常量可以使用任意形式的表达式,如下所示:

#include <stdio.h>
int getNum(){
    return 100;
}
int main(){
    int n = 90;
    const int MaxNum1 = getNum();  //运行时初始化
    const int MaxNum2 = n;  //运行时初始化
    const int MaxNum3 = 80;  //编译时初始化
    printf("%d, %d, %d\n", MaxNum1, MaxNum2, MaxNum3);
    return 0;
}
-------------------------------------------------------------------
运行结果:
100, 90, 80

const 和指针

const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据。const 和指针一起使用会有几种不同的顺序,如下所示:

const int *p1;
int const *p2;
int * const p3;

在最后一种情况下,指针是只读的,也就是 p3 本身的值不能被修改;在前面两种情况下,指针所指向的数据是只读的,也就是 p1、p2 本身的值可以修改(指向不同的数据),但它们指向的数据不能被修改。

当然,指针本身和它指向的数据都有可能是只读的,下面的两种写法能够做到这一点:

const int * const p4;
int const * const p5;

const 和指针结合的写法多少有点让初学者摸不着头脑,大家可以这样来记忆:const 离变量名近就是用来修饰指针变量的,离变量名远就是用来修饰指针指向的数据,如果近的和远的都有,那么就同时修饰指针变量以及它指向的数据。

const 和函数形参

在C语言中,单独定义 const 变量没有明显的优势,完全可以使用#define命令代替。const 通常用在函数形参中,如果形参是一个指针,为了防止在函数内部修改指针指向的数据,就可以用 const 来限制。

在C语言标准库中,有很多函数的形参都被 const 限制了,下面是部分函数的原型:

size_t strlen ( const char * str );
int strcmp ( const char * str1, const char * str2 );
char * strcat ( char * destination, const char * source );
char * strcpy ( char * destination, const char * source );
int system (const char* command);
int puts ( const char * str );
int printf ( const char * format, ... );
四.随机数

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值