初识C语言

本文是C语言的基础教程,涵盖了C语言的起源、发展和ASCII码,讲解了C语言的编译器、数据类型、变量、常量、字符串、转义字符、注释、选择语句、循环语句、函数、数组、操作符、关键字等内容。通过实例解析了变量的作用域、生命周期、指针、结构体以及内存管理,帮助初学者理解C语言的基本概念和编程技巧。
摘要由CSDN通过智能技术生成

文章目录

初识C语言

注:如果说化学是一门以实验为基础的学科,那么计算机一定以动手实际敲代码为基础.

我们要会写,也要会看他人写的代码.理解与学习高手写的代码,也是我们进步的重要途径.

细碎的知识点无法做到较为全面的扫盲,因此,作者写了如下知识点脉络。

以供学习者的参考与自己的复习参考。

万丈高楼平地起,在初始C语言部分,我们可以将其看作领略C语言知识库的一扇装饰丰富的大门,亦或是一本宏大书籍的小序.C的魅力要我们在以后的学习中一同领略.

以下代码均是笔者在 VS2019 环境下编译的。

天外有天,作者会在后续学习中不断完善出新。希望保持与读者的交流!

1.什么是C语言

类比人和人交流的语言:汉语、德语、葡萄牙语、法语……

C语言是人和计算机交流的语言,为通用计算机编程语言,广泛用于底层开发(不代表不可用于上层开发,如Linux、早期的WPS)。

人和计算机交流的语言还有:C++、Java、Python……

目前已知计算机已有上千种,C语言经久不衰。

底层开发(应用软件之下的)

为让电脑(硬件)工作起来,我们需要装操作系统(win/Mac/Linux),在系统上可以装上层应用软件(QQ、WeChat)。操作系统和硬件间的驱动层,驱动层将两者关联,操作系统调用驱动层来关联硬件,使其工作。

应用软件(QQ、WeChat)
操作系统(win/Mac/Linux)
驱动层
电脑(硬件)

1.1 C语言的发展

二进制序列(如:1001)ADD助记符
编译为可执行程序(二进制)C语言/C++/Java/Python高级计算机语言

1.2 ASCII(为统一而生的表)

在这里插入图片描述

为了统一做出的努力:

K&R,C语言的创始人。

二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。 [1] 目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11(C89最早 C90 C89 C99 C11……) 标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。

C语言常见的编译器

Clang GCC WIN-TC SUBLIME MSVC Turbo C等

2.第一个C语言程序

VS 2019:集成开发环境——IDE(创建与使用)

#include <stdio.h>
int main()
    //int函数返回类型:整型
    //void main()写法古早,不推荐
{
printf("hello beauty!\n");// \n换行,""引起的是字符串
    //printf是库函数,函数的使用需要包含头文件stdio.h
return 0;
//C语言习惯,返回0为正常返回,返回非0表示异常返回
}
//写好代码后,ctrl+f5运行(菜单栏:调试:开始执行(不调适))
//VS:编译+链接+运行

//这样写法可以:
int main(void)
    //void表示main函数不需要参数
{
    return 0;
}

//ctrl+k+c 注释
//ctrl+k+u 取消注释

main函数有且仅有一个,是程序的入口:按键盘上的f10或fn+f10,从main函数进入,逐句执行。

3.数据类型

char字符数据类型
short短整型
int整型
long长整型
long long更长的整型
float单精度浮点型
double双精度浮点型
思维:写代码解决生活中的问题(线上购物时)

线下:货架上选商品,购物车,收银台结账

线上:商品,选商品,购物车,结算

命名规则的部分解析:

35整数;3.5小数

1.234=12.34*10^-1小数点浮动的小数

#include <stdio.h>
int main()
{
    printf("%d\n",sizeof(char));//1bit
    //%d,打印十进制的整数
    printf("%d\n", sizeof(long));//4
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof(short));//2
	printf("%d\n", sizeof(float));//4
	printf("%d\n", sizeof(double));//8
	printf("%d\n", sizeof(long long));//8
	printf("%d\n", sizeof(long double));
   return 0;
}
//存在这么多类型其实是为了更加丰富的表达生活中的各种值。
//C语言标准规定:long满足sizeof(long)>=sizeof(int)即可,故long:4 byte or 8 byte 

  • // 后的单位:字节( 1 bit =存储数据的一个空间)
从小到大一些中文名称与单位换算
bit比特
byte字节 1 byte = 8 bit (字节跳动:ByteDance)
KB1 KB = 1024 byte
MB1 MB= 1024 KB
GB1 GB = 1024 MB
TB1 TB = 1024 GB
PB1 PB = 1024 TB
计算机能够处理的是2进制:
十进制2进制八进制十六进制
0-90-10-70-9 、a-f
//类型的使用:
char ch='w';
int weight=129;
int salary=20000;

4.变量、常量

生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型等等)。

不变的值,C语言中用常量来表示。

有些值是可变的(比如:年龄、体重、薪水etc)。

4.1定义变量的方法

int age = 150;
float weight = 45.5f;
//类型 变量名=数值
//45.5默认是double类型,加f(45.5f)保证float类型
char ch = 'w';

4.2变量的命名

  • 只能由字母(包括大写和小写)、数字和下划线( _ )组成。
  • 不能以数字开头。
  • 长度不能超过63个字符。
  • 变量名中区分大小写的。
  • 变量名不能使用关键字

注:变量名尽量取的有意义,避免一直用alphabet的无意义的a-z

4.3变量的分类

4.3.1局部变量(大括号内部的)
void test()
{
    int c;
}
int main()
{
    int a=10;
    return 0;
}
4.3.2全局变量(大括号外部的)
#include <stdio.h>
int main()
int global=2022;//全局变量
{
   int local=2011;//局部变量
   int global=2020;//局部变量
    printf("global=%d\n",global);//2020
    return 0;
}
总结:

上面的局部变量global变量的定义其实没有什么问题的。

当局部变量和全局变量同名的时候,局部变量优先使用。

4.4变量的使用

写一个函数计算两个整数的和
#include <stdio.h>
int main()
{
    int num1 = 0;
    int num2 = 0;
	int sum = 0;
    printf("输入两个操作数:>");
   //1.输入两个整数
    scanf("%d %d",&num1,&num2);
   //2.求和
    sum=num1+num2;
   //3.输出
    printf("sum=%d\n",sum);
    return 0;
}

4.5变量的作用域和生命周期

int main()
{
    {
        int a=10;
        printf("1:%d\n",a);
    }
    printf("2:%d\n",a);//报错,a=10出大括号以销毁
    return 0}

全局变量在任何位置都可以使用,甚至可以跨文件使用。又可被任意改变,因此不安全。

//全局变量
int g_val=2011;

//extern用来声明外部符号
extern int g_val;
int main()
{
    printf("%d\n",g_val);
    return 0;
}
4.5.1作用域

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。

1.局部变量的作用域是变量所在的局部范围。

2.全局变量的作用域是整个工程。

4.5.2生命周期

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。

  1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。

  2. 全局变量的生命周期是:整个程序的生命周期。

4.6常量

C语言中的常量和变量的定义的形式有所差异。

C语言中的常量分为以下几种:

  • 字面常量
  • const 修饰的常变量
  • #define定义的标识符常量
  • 枚举常量
#include <stdio.h>
enum Sex
{
    MALE,
    FEMALE,
    SECRET//最后一个不需要加 逗号
};//大括号后必须加 分号

//括号中的MALE,FEMALE.SECRET是枚举常量
  //枚举常量演示
int main()
{
    enum Sex s=MALE;//性别
    printf("%d\n", MALE);
    printf("%d\n", FEMALE);
    printf("%d\n", SECRET);
    //注:枚举常量的默认是从0开始,依次向下递增1的
    return 0; 
}

int main()
{
    //字面常量演示
    3.14;//浮点字面常量
    1000;//字面常量
    "abcd"//字符串字面值
        '@'//字符字面常量
        'a'//字符字面常量
}

    //const 修饰的常变量
    const float pai = 3.14f;   //这里的pai是const修饰的常变量
    pai = 5.14;//是不能直接修改的!
    
    //例:
    int arr[10]={0};//数组
    
    int n=10;
    int arr[n]={0};//error
    
    const int num=10;//const修饰常变量,本质是变量
    int arr[num]={0};//error
    
    
    //#define的标识符常量 演示
    #define MAX 100
    printf("max = %d\n", MAX);
    MAX=200//err

注:上面例子上的 pai 被称为 const 修饰的常变量, const 修饰的常变量在C语言中只是在语法层面限制了变量 pai 不能直接被改变。

pai本质上还是一个变量,所以叫常变量

5.字符串+转义字符+注释

5.1字符串

"hello beauty.\n"

这样由双引号(Double Quote)引起的一串字符称为字符串字面值(String Literal),或者简称字符串。

注:字符串的结束标志是一个\0的转义字符,不算做字符串内容。

#include <stdio.h>
#include <string.h>
//下面的代码,打印出来的结果是什么?为什么?(突出'\0'的重要性)
int main()
{
    char arr1[] = "bit";
   // 查看隐藏的\0:f10;菜单栏:调试+窗口+监视
    char arr2[] = {'b', 'i', 't'};
    char arr3[] = {'b', 'i', 't''\0'};
    printf("%s\n", arr1);//bit
    printf("%s\n", arr2);//bit烫烫烫烫烫
    printf("%s\n", arr3);//bit
    //string lenth
    //strlen是库函数,是专门求字符串长度的函数,使用需包含头文件<string.h>
    printf("%d\n",strlen(arr1));//3
    printf("%d\n",strlen(arr2));//随机值
    printf("%d\n",strlen(arr3));//3
    return 0;
}
//%s 是打印字符串,遇到\0打印自然结束

5.2转义字符

假如我们要在屏幕上打印一个目录: c:\code\test.c
#include <stdio.h>
int main()
{
 printf("c:\code\test.c\n");
    return 0; 
}

实际上运行结果:

在这里插入图片描述

一些转义字符
转义字符释义
?在书写连续多个问号时使用,防止他们被解析成三字母词 早期编译器:??)——>] ??(——>[
\`用于表示字符常量
\"用于表示一个字符串内部的双引号
\\用于表示一个反斜杠,防止它被解释为一个转义序列符
\a警告字符,蜂鸣
\b退格符
\f进纸符
\n换行
\r回车
\t水平制表符
\v垂直制表符
\dddddd表示1~3个八进制的数字。 如: \130 X
\xdddd表示2个十六进制数字。 如: \x30 0
进制转换
123(十进制)
123
10^210^110^0权重
1*10^32*10^13*10^0sum=123
130(八进制转化为十进制)
130
8^28^18^0权重
1*8^23*8^10*8^0sum=88
二进制 找对应 ASC II 表:130这个8进制数字转化为10进制数字,作为ASC II码值,表示的字符就是‘X’
#include <stdio.h>
int main()
{
    //问题1:在屏幕上打印一个单引号',怎么做?
    //问题2:在屏幕上打印一个字符串,字符串的内容是一个双引号“,怎么做?
    printf("%c\n", '\'');
    printf("%s\n", "\"");
    return 0; 
}
读转义字符的题:
//程序输出什么?
#include <stdio.h>
int main()
{
    printf("%d\n", strlen("abcdef"));
    // \62被解析成一个转义字符
    printf("%d\n", strlen("c:\test\628\test.c"));//14
    return 0; 
}

5.3注释

  1. 代码中有不需要的代码可以直接删除,也可以注释掉

  2. 代码中有些代码比较难懂,可以加一下注释文字

比如:

#include <stdio.h>
int Add(int x, int y)
{
    return x+y; 
}
/*C语言风格注释
int Sub(int x, int y)
{
    return x-y;
}
*/
int main()
{
    //C++注释风格
    //int a = 10;
    //调用Add函数,完成加法
    printf("%d\n", Add(1, 2));
    return 0; 
}
注释有两种风格:
  • C语言风格的注释 /* */ ;缺陷:不能嵌套注释

  • C++风格的注释 // ; 可以注释一行也可以注释多行(推荐)

6.选择语句

实现非黑即白的选择语句时,我们可以使用选择语句。(以下示例为作者喜好编写)

在这里插入图片描述

#include <stdio.h>
int main()
{
    int coding = 0;
    printf("你想要成为rap star吗?(选择1 or 0):>");
    scanf("%d", &coding);
    if(coding == 1)
   {
       prinf("坚持,跟马思唯当同事\n");
   }
    else
   {
       printf("放弃,做做白日梦就好啦\n");
   }
    return 0;
}

7.循环语句(while循环)

循环往复的做一件事,如日复一日地坚持“日出而作日落而息”。

在这里插入图片描述

int main()
{
    int a=1;
    int b=1;
    while(a<7)
    {
        b=b-a;
        a=a+2;
    }
    if(7==a)
        printf("a=%d\n",a);
    return 0;
}

8.函数

#include <stdio.h>
int main()
{
    int num1 = 0;
    int num2 = 0;
    int sum = 0;
    printf("输入两个操作数:>");
    scanf("%d %d", &num1, &num2);
    sum = num1 + num2;
    printf("sum = %d\n", sum);
    return 0; 
}

//上述代码,写成函数如下:
#include <stdio.h>
int Add(int x, int y) 
//返回类型 函数名 函数参数
{
   int z = x+y;
   return z;
}//函数体
int main()
{
    int num1 = 0;
    int num2 = 0;
    int sum = 0;
    printf("输入两个操作数:>");
    scanf("%d %d", &num1, &num2);//不要轻易加\n
    sum = Add(num1, num2);
    printf("sum = %d\n", sum);
    return 0; 
}

函数的特点就是简化代码,代码复用

9.数组

要存储1-10的数字,怎么存储?

C语言中给了数组的定义:一组相同类型元素的集合。

9.1数组定义

int main()
{
    //定义
    int arr[10];
    char ch[5];
    int count[3];

//初始化
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
    int arr1[10]={1,2,3};//不完全初始化,只初始化前三个值,剩余的初始化为0
    int arr2[]={1,2,3};
    int arr3[];//error
    int arr4[10];//不推荐
    return 0}
C99 (gcc)编译器下可运行的:
int main()
{
    int n=0;
    int arr[n];
    //C99 变长数组,允许数组在创建的时候,数组大小用变量指定,但是这种数组不能初始化
    return 0;
}

9.2数组的下标

C语言规定:数组的每个元素都有一个下标,下标是从0开始的。

数组可以通过下标来访问的。

比如:

int arr[10] = {0};
//如果数组10个元素,下标的范围是0-9

在这里插入图片描述

9.3数组的使用

#include <stdio.h>
int main()
{
 int i = 0;
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
 for(i=0; i<10; i++)
 {
       printf("%d ", arr[i]);
 }
 printf("\n");
    return 0; 
}

#include <stdio.h>
int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    int i=0;
    while(i<10)
    {
        printf("%d",arr[i]);
        i++;
    }
    return 0; 
}

#include <stdio.h>
int main()
{
     int arr[10] = {1,2,3,4,5,6,7,8,9,10};
     int i = 0;
     while(i<10)
     {
         //输入
           scanf("%d",&arr[i]);
           i++;
     }
    int j=0;
    while(j<10)
    {
        //输出
        printf("%d",arr[j]);
        j++;
    }
   return 0; 
}

10.操作符

10.1算术操作符

+(加) -(减) *(乘) %(取余or取模) /(除)
10.1.1关于除法运算
int main()
{
    printf("%d\n",8/2);//得4
   
    printf("%d\n",7/2);//得3
    //为何出现值不是3.5?
    //除号两端为整数,故计算结果为整数
    //数学计算来说:7/2=3...1(3余1)
    
    //令结果位小数:
    printf("%lf\n",7/2.0);//得3.500000
    //注意:d变为lf,2变为2.0
    
    
    //若想仅得到3.5:
    printf("%.1lf\n",7/2.0);//得3.5
    //注意:lf变为.1lf,表示小数点后保留1位小数
    
    //同理,也可写为:
     printf("%.1lf\n",7.0/2);//也得3.5
    return 0}
10.1.2关于取模(取余)运算
a.不能整除
int main()
{
    printf("%d\n",7%2);//得1
    //数学运算:7/2=3...1(3余1)
    return 0;
}
b.能整除
int main()
{
    printf("%d\n",8%2);//得0
    //数学运算:8/2=4...0(4余0)
    return 0;
}
c.写判断能否整除的代码(详细见作者初始C语言刷题记录)

10.2移位操作符

>> << (二进制位的移动运算)
int a=1
4字节=32bit
00000000 00000000 00000000 00000001(1的二进制序列)(移位的对象)

10.3位操作符(位:二进制位)

&按位与
^按位异或
|按位或

10.4赋值操作符

= 复合赋值符:+= -= *= /= &= ^= |= >>= <<=
//一些举例
a = a + 5;
a += 5;

a = a-3;
a -=3;

在这里插入图片描述

10.5单目操作符(只有一个操作数的操作符)

!逻辑反操作(假变真,真变假,真假转换)
-负值
+真值
&取地址(常运用于指针)
sizeof操作数的类型长度(以字节为单位);不是函数
~对一个数的二进制按位取反
前置(先–后使用)、后置–
++前置(先++后使用)、后置++
*间接访问操作符(解引用操作符)
(类型)强制类型转换

C语言中如何表示真假

0表示假,非0表示真。

10.5.1 !用法举例
a、基础理解
int main()
{
    int a=0;
    scanf("%d",&a);//5
    printf("%d\n",a);//5
    printf("%d\n",!a);//0
    return 0;
}

int main()
{
    int a=0;
    scanf("%d",&a);//0
    printf("%d\n",a);//0
    printf("%d\n",!a);//1,语法规定
    return 0;
}
b、实例
int main()
{
    int flag=0;
    if(flag)//flag为真,打印HI
    {
        printf("HI\n");
    }
    if(!flag)//flag为假,打印FINE
    {
        printf("FINE\n");
    }
    return 0}
10.5.2 -用法举例
int main()
{
    int a=-10;
    int b=-a;
    printf("%d\n",b);
    return 0;
}
10.5.3 sizeof相关知识点讲解
int main()
{
    int a =0;
    printf("%d\n",sizeof(a));//4字节,建议写法
    printf("%d\n",sizeof a );//4字节,说明sizeof不是函数,是操作符
    //或者写成
    printf("%d\n",sizeof(int));//4字节
    printf("%d\n",sizeof int );//error
    return 0;
}
与 strlen 的区分
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[]="abc";
    //a b c \0
    char arr2[]={'a','b','c'};
    //a b c
    printf("%d\n",strlen(arr1));//3
    printf("%d\n",strlen(arr2));//15(随机数)
    printf("%d\n",sizeof(arr1));//4
    printf("%d\n",sizeof(arr2));//3
    return 0;
}
a. srtlen
  • 库函数
  • 用来求字符串长度(关注的字符串中是否有\0,统计\0之前出现的字符个数)
b. sizeof
  • 操作符

  • 只关注内存空间的大小:占据了多大的内存空间

int main()
{
    int arr[10]={0};
    printf("%d\n",sizeof(arr));//40,计算的是数组的总大小,单位是字节
    printf("%d\n",sizeof(arr[0]));//4,
    printf("%d\n",sizeof(arr)/sizeof(arr[0]));//计算数组的元素个数:40/4=10
    return 0;
}
10.5.4 前置or后置–、++
int main()
{
    int a =10;
    int b=++a;//前置++,先使用,再++ b=a,
         //a = a + 1, b = a

    int c=a++;//后置++,先使用,后++
    //c = a,a = a + 1
    printf("a=%d b=%d c=%d\n",a,b,c);
    
    int b=--a;
    //a=a-1,b=a
    
    int b=a--;
    //b=a,a=a-1
    return 0;
}
10.5.5 强制类型转换
int main()
{
  //int       double
    int a=(int)3.14;
    printf("%d\n",a);//强制转化为整型,3.14——>3
    return 0;
}//强制类型转换并非所有情况下都使用

10.6关系操作符

>
>=
<
<=
!=用于测试“不相等”;注意与数学符号的区分
==用于测试“相等“。=:赋值;==:判断。
int main()
{
    int age=10;
    if(18<=age<=35)//错误写法
 //该语句的逻辑(0<=35)  18<=10逻辑为假得结果:0
     
    //改写
    if(age>=18 && age<=35)
    {
       printf("青年\n");
    }
    return 0;
}

10.7逻辑操作符

&&逻辑与(并且)
||逻辑或(或者)
10.7.1代码举例(并且 or 或者)
int main()
{
    int a=0;
    int b=5;
   
    if(a && b)//并且
    {
        printf("allure\n");//由0,不执行该语句
    }
    
    if(a||b)//或者
    {
     printf("allure\n");//打印   
    }
}

10.8条件操作符(三目操作符)

exp1? exp2: exp3(表达式1为真,运行表达式2;表达式1为假,运行表达式3)
10.8.1在循环语句中的等价写法举例(比大小,取较大值)
int main()
{
    int a=0;
    int b=0;
    int c=0;
    if(a>b)
        m=a;
    else
        m=b;
}
等价于:m=(a>b?a:b);

10.9逗号表达式

exp1 , exp2 , exp3 , … expN
10.9.1(从左往右依次计算)
int main()
{
    int a=3;
    int b=0;
    int c=4;
    int d=(a=b-3,b=a+c,c=a-b,a=c+3);
        // a=-3  b=1   c=-4  a=-1 
    printf("%d\n",d);//-1
    return 0;
}

10.10下标引用、函数调用和结构成员

[ ] :下标引用操作符 ( ) :函数调用操作符 结构体中使用: . ->
10.10.1 下标引用操作符 和 函数调用操作符 的 代码介绍
int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    printf("%d\n",arr[7]);//[]就是下标引用操作符,arr,7
    return 0;
}

//函数调用操作符
int Add(int x,int y)
{
    return x+y;
}
int main()
{
    int a=10;
    int b=20;
    int c=Add(a,b);//( )就是函数调用操作符
    return 0}

11.常见关键字

auto自动 break停止、default (switch case语句中,实现循环)for、while、do char、short、int、long 、double、float (const,类型里面修饰变量) extern(声明外部符号) goto(可用来实现分支也可用来实现循环) sizeof 计算类型的大小 static修饰变量 struct结构体 、enum 枚举(自定义类型)、union联合体/共用体(自定义类型) continue 继续 if、else(实现分支) typedef 类型重定义unsigned 无符号的 signed 有符号的 void 无类型/空类型(函数返回值、函数参数)volatile return(函数中返回)register(寄存器关键字)

本质上所有局部变量都是auto(自动)变量:自动创建自动销毁。

//对unsigned的一些解释
int main()
{
    int a=10;
    unsigned int num=-10;//unsigned将放入的数值当作正整数处理
    return 0;
}

注:C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。

11.1 register 寄存器关键字

寄存器:计算机上的一种存储设备

字节寄存器<=>CPU(集成,相互传输)
xx M高速缓存(cache)
8 G / 16 G内存 于 CPU(中央处理器)相互传输数据(早期读写)
500 G硬盘
2 T网盘

上述,由下往上:

速度:加快占用空间:变小
int main()
{
    //register起建议作用,并非决定性作用
    register int num=10;   
    return 0;
}
//现在编译器自动判断是否将数据加入寄存器

11.2 关键字typedef(类型重命名)

typedef unsigned int uint_32;//将unsigned int重命名为的uint_32也是一个类型名
int main()
{
//num1和num2,这两个变量的类型是一样的
    unsigned int num1=0;
    uint_32 num2=0;
    return 0;
}

typedef struct Node
{
    int data;
    struct Node* next;
}Node;

11.3关键字static(修饰变量和函数,可以看成对程序或语句的一些保护)

void test()
{
    int a=1;
    //上行改为:static int a=1;
    //被static修饰后,局部变量不会被销毁
    a++;
    printf("%d",a);
}
int main()
{
    int i=0;
    while(i<10)
    {
        test();
        i++;
    }
    return 0;
}
//原本运行结果10个2
//修改后运行结果:2 3 4 5 6 7 8 9 10 11
内存划分区域:
栈区局部变量、函数的参数(进入范围创建,出范围销毁)
堆区动态内存的分配、malloc、calloc、realloc、free
静态区静态变量、全局变量

static,静态变量的生命周期就是整个程序的生命周期,在程序结束后静态变量才回收空间。

static修饰局部变量的时候,改变了变量的存储类型,普通的局部变量储存在栈区,被static修饰的变量存储在静态区。

存储在静态区的变量,出了作用域不会销毁,依然存在。

总结:
  • 生命周期:变长
  • 作用域:没变
11.3.1修饰局部变量(静态局部变量)
#include <stdio.h>
void test()
{
    int i=0;
//上句修改为: static int i = 0;
    i++;
    printf("%d",i);
}
int main()
{
    int i=0;
    for(i=0;i<10;i++)
    {
        test();
    }
    return 0;
}
结论:

static修饰局部变量改变了变量的生命周期。

让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。

11.3.2修饰全局变量(静态全局变量)
//源文件下两个文件:add.c和test.c
//add.c
int g_val = 2018;
//修改为:static int g_val = 2018;

//test.c
extern int g_val = 2018;
//声明外部函数
int main()
{
    printf("%d\n", g_val);
    return 0; 
}

修改后代码在编译的时候会出现连接性错误

过程:

编译+链接:生成可执行文件 exe

结论:

一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。

解释:

全局变量具有外部链接属性,static修饰全局变量的时候,由外部连接属性改为了内部连接属性。

这个全局变量只能在自己所在的.c文件中看到,其他源文件看不到了。

11.3.3修饰函数(静态函数)(类似于static修饰全局变量)
//源文件下两个文件:add.c和test.c
//add.c
int Add(int x, int y)
//上述语句修改为:static int Add(int x, int y) 
{
    return c+y; 
}

//test.c
extern int Add(int x, int y);
//声明外部函数
int main()
{
    printf("%d\n", Add(2, 3));
    return 0;
}

修改后代码在编译的时候会出现连接性错误

结论:

一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。

解释:

函数本身是具有外部连接属性,如果static修饰函数,函数的外部链接属性就变成了内部链接属性,这个函数只能在自己所在的源文件内部使用,其他源文件无法使用该函数。

static使用场景:

避免源文件下不同文件对相同定义赋予不同值造成的使用上的冲突。

使用较少。视情况而定。

12. #define可以定义常量和宏

#define和#include为预处理指令

12.1 define定义标识符常量

#include <stdio.h>
//运用在数组中
#define SIZE 10
//名称,如SIZE可自行修改
int main()
{
    int arr[SIZE];
    printf("%d\n",SIZE);
    return 0;
}

12.2 define定义宏(宏是有参数的,和函数很像)

int Add(int x,int y)
{
    return x+y;
}
int main()
{
    int a=10;
    int b=20;
    int sum1=Add(a,b);
    printf("sum1=%d\n",sum1);
    return 0;
}

//写成宏
#define ADD(x, y) ((x)+(y))
//注意:ADD全大写
int main()
{
    int a=10;
    int b=20;
    int sum1=Add(a,b);
    printf("sum1=%d\n",sum1);
    int sum2=((a)+(b));
    printf("sum2=%d\n",sum2);
    return 0;
}

//另一个例子
#define ADD(x, y) ((x)+(y))
#include <stdio.h>
int main()
{
    int sum = ADD(2, 3);
    //与类型无关
    printf("sum = %d\n", sum);
    sum = 10*ADD(2, 3);
    printf("sum = %d\n", sum);
    return 0; 
}
12.2.1宏和函数近距离对比(后续博客会更新详细版)
int Add(int x,int y)
#define ADD (x,y) ((x)+(y))

13.指针

13.1内存

内存是电脑上特别重要的存储器计算机中程序的运行都是在内存(8G、12G、32Getc)中进行的

所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节

为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址

变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。

32位机器上有32根地址线,通电进行0/1变换。

在这里插入图片描述

内存单元的编号——>地址——>指针

编号=地址=指针

13.1.1取出变量地址如下:
#include <stdio.h>
int main()
{
    int num = 10;
    &num;//取出num的地址
    //注:这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)
    printf("%p\n", &num);//打印地址,%p是以地址的形式打印,显示16进制数字
    //看监视器:调试(D)——>窗口(w)——>内存(M)
    return 0;
}

在这里插入图片描述

二进制到16进制(转化后倒放)
十六进制:0——9、a——f
int a=10;在内存中存储十进制的10
00000000 00000000 00000000 0000101032位二进制中表现形式
0x 00 00 00 0a转化后的16进制表现形式
0a 00 00 00 00显示取地址后的形式

13.2定义指针变量

地址如何存储?——>需要定义指针变量。

int num = 10;
int *p;//p为一个 整型 指针变量
//*说明p为指针变量
//int说明p指向对象为int型
p = &num;//&取地址操作符
//p指针变量对应的4个字节以首地址的形式表示出来
13.2.1指针的使用实例(重要的基础知识):
#include <stdio.h>
//指针,本质是地址
//口头语中,说的指针是指:指针变量
int main()
{
    int num = 10;
    int *p = &num;//&取地址操作
    *p = 20;//*解引用操作
    return 0; 
}

在这里插入图片描述

13.3指针变量的大小

要想知道“指针变量有多大?”

就要知道指针变量存储的是什么?——>地址

故,指针变量的大小取决于地址的大小。

  • 32位机器 — 一个地址是32个二进制位,存储需要32个bit位的空间,所以32位机器上,指针变量的大小是4个字节
  • 64位机器 — 一个地址是64个二进制位,存储需要64个bit位的空间,所以64位机器上,指针变量的大小是8个字节
  • 最终取决于编出的程序是32位或64位(打开任务管理器)

在这里插入图片描述

#include <stdio.h>
int main()
{
    printf("%zu\n", sizeof(char *));
    //zu专门用来打印sizeof的返回值
    printf("%zu\n", sizeof(short *));
    printf("%zu\n", sizeof(int *));
    printf("%zu\n", sizeof(double *));
    //4(x86环境)
    //8(x64环境)
    return 0; 
}
结论:指针大小在32位平台是4个字节,64位平台是8个字节。

13.4代码举例

void test(double* pd)
{
    *pd=5.6;
}
int main()
{
    double d=3.14;
    test(&d);
    double*pd=&d;
        *pd=5.6;
    //而不是简单的:d=5.6;
    printf("%lf\n",d);
    return 0;
}

14.结构体

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。

比如描述学生,学生包含:名字+年龄+性别+学号 这几项信息(只能使用结构体来描述)。

在这里插入图片描述

代码举例:

struct Stu
{
    char name[20];//名字
    int age;      //年龄
    char sex[5];  //性别
    char id[15]//学号
};

结构体的初始化:

void print(struct Stru*ps)
{
    printf("%s %d %s %s\n",(*ps).name,(*ps).age,(*ps).sex,(*ps).id);    //结构体变量.结构体成员
    printf("%s %d %s %s\n",ps->name,ps->age,ps->sex,ps->id);            //结构体指针->结构体成员
}
int main()
{
    //打印结构体信息
    struct Stu s = {"小李"20"男""20220114"};//将类型实例化变为结构体变量
    //输入
    scanf("%s %s %s %s",s.name,s.sex,s.id,&(s.age));
    printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);//.为结构成员访问操作符
    printf(&s);
    //struct Stu *ps = &s;
    printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps- >id);//->操作符
    return 0;
}
#include <stdio.h>
int main()
{
    printf("%zu\n", sizeof(char *));
    //zu专门用来打印sizeof的返回值
    printf("%zu\n", sizeof(short *));
    printf("%zu\n", sizeof(int *));
    printf("%zu\n", sizeof(double *));
    //4(x86环境)
    //8(x64环境)
    return 0; 
}

13.4代码举例

void test(double* pd)
{
    *pd=5.6;
}
int main()
{
    double d=3.14;
    test(&d);
    double*pd=&d;
        *pd=5.6;
    //而不是简单的:d=5.6;
    printf("%lf\n",d);
    return 0;
}

14.结构体

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。

比如描述学生,学生包含:名字+年龄+性别+学号 这几项信息(只能使用结构体来描述)。

代码举例:

struct Stu
{
    char name[20];//名字
    int age;      //年龄
    char sex[5];  //性别
    char id[15]//学号
};

结构体的初始化:

void print(struct Stru*ps)
{
    printf("%s %d %s %s\n",(*ps).name,(*ps).age,(*ps).sex,(*ps).id);    //结构体变量.结构体成员
    printf("%s %d %s %s\n",ps->name,ps->age,ps->sex,ps->id);            //结构体指针->结构体成员
}
int main()
{
    //打印结构体信息
    struct Stu s = {"小李"20"男""20220114"};//将类型实例化变为结构体变量
    //输入
    scanf("%s %s %s %s",s.name,s.sex,s.id,&(s.age));
    printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);//.为结构成员访问操作符
    printf(&s);
    //struct Stu *ps = &s;
    printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps- >id);//->操作符
    return 0;
}

15.函数如果不写返回值:

函数默认会返回一个值。

有些编译器上返回的是:最后一条指令产品的结果。

但这种写法本身是不合规定的

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值