【C】 C语言入门——带你从0开始

简介: 【C】 C语言入门——带你从0开始

前言

  • 讲解C语言学习的一些基础知识,了解C语言大概有哪些知识点,但每个知识点不做太过详细的讲解
  • 这篇博客旨在先让大家对C语言的知识有一个大概的轮廓,提高学习能力
  • 之后会对每个知识点做出详细的总结与分析

73d8c9be8b2a4960a39693770de0ac9a.png

  • 你若盛开,花香自来

1. 什么是C语言.

C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSIC,作为C语言最初的标准。 [1] 目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准。

C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。

通俗点来讲,C语言是人与计算机进行交互的语言,把我们的想法通过计算机来实现,可以说C语言是其他众多高级语言的鼻祖语言,所以我们要学习编程首先从C语言学起是非常重要的。

2. 第一个C语言程序.

写程序对于初学者,建议使用vs的编译环境,对初学者较为友好;可以使2022/2019/2013/2010等版本,但2010如果在之后要学习C++是不支持编译的。使用vs编译器可能会遇到scanf报错的问题,解决办法可以看我的另一篇博客https://blog.csdn.net/Trong_/article/details/123994821

让我们简单的先来写一段代码

#include<stdio.h>    //这里是预处理命令
int main()     //定义一个主函数
{
     //在双引号的中间输入Hello world!
  printf("Hello world!\n");  //是一个格式输出的库函数,此时实现在控制台打印一个Hello world!
  return 0;  //函数结束的标志
               //函数结束时返回函数值0
}

附运行结果

73d8c9be8b2a4960a39693770de0ac9a.png

要注意的是一个程序只能有一个主函数,而且C语言代码中一定要有一个intmain()作为主函数,可以看作一个程序的入口,也可以看作是唯一的一个入口,注意程序一定是从主函数开始往后执行的,前面的 int 是一个整形类型,在这里说明函数的返回值是一个整型,与 return 0 ; 相对应。

可能在一些书上主函数还有这样一中写法voidmain(),但这种写法太过于古老,不推荐使用。

return 0;这里的返回值不是一定要是0,可以是任意值,这里写0是大家的一种共识,当然,写其他值肯定也是没有错的。

printf(" ");要使用是要引用一个头文件的,也就是上面代码的第一行,通俗点理解就是你要使用我这个函数,要提前打一下招呼,怎么打招呼呢,就是程序的第一行了。

\n的作用是换行,是一个转义字符,C语言规定以分号;作为一条语句的结束。

3. 数据类型.

73d8c9be8b2a4960a39693770de0ac9a.png

初学先只介绍一些一些基本的数据类型

那么你们是否好奇为什么要搞这么多的数据类型呢,其实不难理解,在我们的生活当中比如我们支付,或者是在做一些其他事情的时候是不是总要接触一些数据,而这些数据有小数,整数等。

整形可以看做一些整数,如60这个数就是一个整型,C语言中的整型有以下四种:

short                    短整型
int                        整型                                (不带有小数)
long                     长整型
long long              更长的整型
  • 浮点型可以看作是一些个小数,如66.6这个数的类型就是一个典型的浮点型,浮点型有以下俩种:
float          单精度浮点数
double      双精度浮点数

字符类型用来储存字符,比如字母w就是一个字符,要注意字符的表示要用英文输入法下的单引号括起来,例如以下代码。

char ch = 'w';        //字符数据类型的使用
int a = 60 ;         //整形的使用
douuble b = 66.6;    //浮点型的使用

那么整形中的长短和和浮点型的单双精度这样区分是为什么呢?其实在计算机中数据的存储是要申请空间的,不同的类型存储数据所占的内存是不同的,整形中长的比短的所占的空间可能要大一些;而浮点型中精度越高,所占的内存空间越大。

  • 这里就要介绍一下计算机中的内存单位了,各个单位之间的换算如下所示

73d8c9be8b2a4960a39693770de0ac9a.png

那这里我们就来验证一下不同类型在计算机中所占的空间大小,如下:

#include<stdio.h>
int main()
{
  printf("%zu\n", sizeof(char));
  printf("%zu\n", sizeof(short));
  printf("%zu\n", sizeof(int));
  printf("%zu\n", sizeof(long));
  printf("%zu\n", sizeof(long long));
  printf("%zu\n", sizeof(float));
  printf("%zu\n", sizeof(double));
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

这里要注意所打印出来的大小是以字节为单位的,可能有人看了这个结果还会有一些疑问,int和long打印出来的空间大小为什么是相同的,不应该是一大一小吗?

其实C语言规定:sizeof(long)>=sizeof(int)就可以

上面%zu是用来打印sizeof()返回的数据类型,类似的
%d用来打印整型
%f打印单精度浮点数
%lf打印双精度浮点数
%c打印字符
%s打印字符串
printf("%d",b);           //使用格式

注:要注意字符串没有对应的数据类型,可以用数组进行存储

那还有其他数据类型在后面的篇幅会介绍到

4. 变量、常量.

联系我们的生活实际我们可以说,固定不能改变的量就是常量,如我们的血型;而一些可以被改变的值就是变量,比如随着时间的推移,我们的年龄,体重等。

4.1 定义变量的方法.

  • 变量定义的形式为:数据类型 变量名;
  • 要注意变量一定是先定义,后使用,这个顺序绝不能搞错。

73d8c9be8b2a4960a39693770de0ac9a.png

int age = 15;     //给变量定义及赋值
float weight = 45.5;
char ch = 'w';

73d8c9be8b2a4960a39693770de0ac9a.png

4.2 变量的分类.

  • 局部变量和全局变量

那么我们先来看一段代码

#include <stdio.h>
int b = 20;         //全局变量
int a = 30;
int main()
{
  int a = 10;     //局部变量
  printf("a=%d\n", a);
  printf("a=%d\n", b);
  return 0;       //那么这里在上面已经定义了局部变量a,这里会不会有问题呢?
}
  • 像上面在{ }在内部定义的变量叫局部变量,在{}外部定义的变量叫全局变量。

大家思考一下我们创建了俩个变量a会不会有问题呢,我们来看一下这段代码的运行结果

73d8c9be8b2a4960a39693770de0ac9a.png

  • 从运行结果来看代码是可以正确编译的,所以,上面的代码是没有问题的,当全局变量和局部变量名字相同的情况下,局部优先;但是为了代码的可观性建议不要将全局和局部变量的名字写成一样的。

4.3 变量的使用.

使用方法我们看一段代码进行理解

73d8c9be8b2a4960a39693770de0ac9a.png

//写一个代码,计算2个整数的和
#include <stdio.h>
int main()
{
  int num1 = 0;
  int num2 = 0;//初始化
  //输入2个整数
  scanf("%d %d", &num1, &num2);//sccanf是一个格式输出函数
  //求和
  int sum = num1 + num2;
  //输出
  printf("%d\n", sum);
  return 0;
}

对变量进行初始化是我们在编译过程中应该养成的一个好习惯,同时可以避免一些编译器的报错而影响正常的编译,还要知道的是当我们创建变量并对变量进行赋值时实际上是要将数据储存在计算机中,是要向计算申请储存空间的。

4.4 变量的作用域和生命周期.

  • 作用域

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用

的而限定这个名字的可用性的代码范围就是这个名字的作用域。

  1. 局部变量的作用域是变量所在的局部范围。
  2. 全局变量的作用域是整个工程。

生命周期

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

局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束,比如4.3中创建的几个变量,从进入主函数生命周期开始,到return 0;后生命周期结束,要清晰的理解开始与结束。

全局变量的生命周期是:整个程序的生命周期,当整个程序执行结束后,生命周期才会结束。

4.5 常量.

在程序执行的过程中,值不发生改变的量就称为常量

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

1. 字面常量

就是可以直接拿出来就用的量,无需进行定义和赋值,如下:

——整型常量:60

73d8c9be8b2a4960a39693770de0ac9a.png

—— 实型常量:66.6

73d8c9be8b2a4960a39693770de0ac9a.png

—— 字符常量:‘w’

73d8c9be8b2a4960a39693770de0ac9a.png

——字符串常量:”Hello world!”

73d8c9be8b2a4960a39693770de0ac9a.png

printf("%d\n",60);
printf("%f\n",66.6);
printf("%c\n",'w');
printf("%s\n","Hello world!");

2. const 修饰的常变量

73d8c9be8b2a4960a39693770de0ac9a.png

在这里看我们编译的这段代码在编译器中会进行报错,说明此时用const修饰的变量a的值是不可以被改变的,此时的a就叫做常变量;在C语言中,const修饰的a,其实本质是变量,但是不能直接修改,有常量的属性。

3. define 定义的标识符常量

在C语言中可以用一个标识符代表一个常量,这种标识符称为符号常量,即标识符形式的常量,一般用大写字母表示。例如,用PI表示3.14159等。

#include<stdio.h>
#define MAX 100
#define STR "abcdef"
int main()
{
 printf("%d\n", MAX);
 int a = MAX;
 printf("%d\n", a);
 printf("%s\n", STR);
 return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

这段代码中用#define MAX 100命令行定义MAX代表常量100,此后凡在此源程序中出现的MAX在预编译阶段都被100替换。

注意:#define是预处理命令,不可以以“ ; ”号结束。

4. 枚举常量

就是可以被一 一列举出来出来的常量比如一个人的性别,我们通过一些代码帮助大家理解。

#include <stdio.h>
//性别
enum Sex
{
 //枚举常量
 MALE,
 FEMALE,
 SECRET
};
 int main()
 {
 enum Color c = MALE;
 printf("%d\n", MALE);
 printf("%d\n", FEMALE);
 printf("%d\n", SECRET);
 printf("%d\n",c);
 return 0;
}

要注意它的常量属性,它不占用计算机的空间,只有在创建变量对它进行存储时才会申请空间。

73d8c9be8b2a4960a39693770de0ac9a.png

注:从运行结果我们可以知道,枚举常量的默认是从0开始,依次向下递增1的。


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

5.1字符串.

“Hello world!”

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

注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。

#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[] = "bit";
    char arr2[] = { 'b', 'i', 't' };
    char arr3[] = { 'b', 'i', 't', '\0' };
    int len = strlen("abc");//求字符串长度的一个函数,string length    头文件 string.h
    printf("%s\n", arr1);
    printf("%s\n", arr2);
    printf("%s\n", arr3);
  printf("%d\n", strlen(arr1));
  printf("%d\n", strlen(arr2));
  printf("%d\n", len);
    return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

这段代码的打印结果出现了乱码,对比发现只有有\0作为结束标志才可以正确输出,所以正确认识\0作为字符串的结束标志是非常重要的;在求字符串长度时,\0不计入长度,只看\0前面的部分,这里同样要注意结尾是否\0的存在,否如果没有计算机打印出来的会是一个随机数。

5.2 转义字符.

下面是一些转义字符,一些常见且需要知道记忆的我做了重点标注,其他的了解即可

转义字符 释义
\? 在书写连续多个问号时使用,防止他们被解析成三字母词
\' 用于表示字符常量’
\“ 用于表示一个字符串内部的双引号
\\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。
\a 警告字符,蜂鸣
\b 退格符
\f 进纸符
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ddd ddd表示1~3个八进制的数字。 如: \130 X
\xdd dd表示2个十六进制数字。 如: \x30 0

这里附一段代码及运行结果供大家参考,思考熟悉如何使用这些转义字符

#include <stdio.h>
#include <string.h>
int main()
{
  //printf("%s\n", "(are you ok\?\?)");
  //(are you ok]    在一些早期的编译器上??)会被解析成]
  printf("%c\n", '\'');
  printf("abcdef\n");
  printf("%s\n", "abcdef");
  printf("abcd\\0ef\n");
  printf("c:\\test\\test.c\n");
  printf("\a");   //你的电脑会响一声,可以实验一下
  printf("abc\nd\tef\n");
  printf("%c\n", '\130');    //打印的是转换成十进制数后所对应的字符,可在ASCII码表中查看
  printf("%c\n", '\x063');
  printf("%d\n", strlen("qwer t"));                  //提示:8不是八进制数哦
  printf("%d\n", strlen("c:\test\628\test.c"));//这一句是一道面试题目,大家可以着重理解一下。
  printf("\"");
  return 0;                                    
}

73d8c9be8b2a4960a39693770de0ac9a.png

ASCII不需要全部记忆,只需记住几个特殊的,如0(48),a(97) , A(65);其他的就可以按顺序推出来。

73d8c9be8b2a4960a39693770de0ac9a.png

5.3 注释.

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

2. 注释可以对程序进行解释,代码中有些代码比较难懂,可以加注释文字

C语言中可以用的有俩种注释方法

1. C语言风格的注释 /* xxxxxx */

缺陷:不能嵌套注释

2. C++风格的注释 //xxxxxxxx

可以注释一行也可以注释多行

俩种注释方法的优劣与区别可以在编译器中操作感受一下。

6. 选择语句.

生活中我们常常做出选择,举个例子,你要努力成为一个合格的程序员,如果你选择每天坚持敲代码,然后你就可以找到一个好工作;如果你没有去敲代码,那么你找不到工作。

接下来我们用代码实现这个这个选择过程,这里只是先带大家认识一下选择分支结构,不做详细的讲解,在之后会进行详细的讲解更新

if-else语句的基本结构

if(表达式)

{

代码执行部分1

}

else

{

代码执行部分2

}

注意:if()和else后面都没有没有分号,直接写{}

#include <stdio.h>
int main()
{
    int coding = 0;
    printf("你会去敲代码吗?(选择1 or 0):>");
    scanf("%d", &coding);
    if(coding == 1)
   {
       prinf("坚持,你会有好offer\n");
   }
    else
   {
       printf("放弃,找不到工作\n");
   }
    return 0;
}

选择语句还有switch语语句, ? : :选择表达式等;在之后会进行详解


7. 循环语句.

同样的,我们每天都在循环的做着一些事情,比如我们每天都在重复的敲着代码,那么终有一天,我们会拿到一份好offer.

  • C语言中如何实现循环呢?

while语句-讲解

for语句(之后详解)

do … while语句(之后详解)

我们先来了解C语言while循环的结构

while()

{

代码执行部分

}

//while循环的实例
#include <stdio.h>
int main()
{
    int line = 0;
    while(line<=20000)   //当不满足括号中的条件时循环结束
   {
        line++;
        printf("我要继续努力敲代码\n");
   }
    if(line>20000)
        printf("好offer\n");
    return 0;
 }

8. 函数.

上面在讲解变量的时候我们举了一个俩个数进行求和的例子,那在这里用函数如何实现俩个数求和呢,我们通过代码实现帮助理解。

#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);
    sum = Add(num1, num2);   //将要进行计算的俩个参数传给函数
    printf("sum = %d\n", sum);
    return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

当我们创建函数时函数中的变量并没有在计算机中申请空间,只有在使用时才会申请空间。


9. 数组.

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

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

9.1 数组定义.

int arr[10] = {1,2,3,4,5,6,7,8,9,10};      //定义一个整形数组,最多放10个元素

要注意创建一个数组,数组的方括号内必须是一个常量,不可以是变量,其内的数值表示这个数组可以存放的元素个数,同时这个数值是可以省略不写的,省略后会根据后面的元素个数自动确定。

需要知道的是C语言在C99标准之前,数组的大小都是用常量或者常量表达式来指定;而C99标准之后,支持了变长数组,这个时候允许数组的大小是变量,但是这种指定方式的数组是不能初始化的,VS编译器对C99中的一些语法支持不是很好,是不支持变长数组的。

int main()
{
    int m = 100;
    int arr4[m];//C99标准之后支持但不能进行初始化,在vs编译器中是错误的
    return 0;
}

9.2 数组的下标.

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

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

比如:

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

73d8c9be8b2a4960a39693770de0ac9a.png

通过下标可以访问到数组中的每个元素

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;
}

73d8c9be8b2a4960a39693770de0ac9a.png

10. 操作符.

这里我们对一些简单常见的进行了解,后期会结合知识点详细讲解。

  • 操作符有单目/双目/三目操作,分别对应着操作数的不同,结合下面的内容进行理解。

73d8c9be8b2a4960a39693770de0ac9a.png

按顺序分别对应着加、减、乘、除、取模(就是取余数);属于双目操作符,对应着俩个操作数,如:a + b

强调一些除法和取模需要注意的点:

1. 除号的两端都是整数的时候,执行的是整数除法,如果两端只要有一个浮点数就执行浮点数的除法

2. 取模操作符的两个操作符只能是整数

73d8c9be8b2a4960a39693770de0ac9a.png

双目操作符

73d8c9be8b2a4960a39693770de0ac9a.png

注意这里这个=可不是等号,它是赋值号,如:int a = 1;是把1赋给变量a;要与等号区分,C语言中的等号用==来表示。关于其他的赋值号大家联系下面这段代码理解,一样的道理。

int main()
{
   int a = 0;//初始化
   a = 20;//赋值
   a = a + 3;//a=23
   a += 3;//这俩个式子是等价的
   a -= 3;
   a = a - 3;//同样也是等价的
   return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

结合下面的代码和注释进行理解

!

C语言中
0表示假
非0表示真
 int flag = 2;//真
 if (!flag)//假,不会打印结果
 {
     printf("hehe\n");
 }

+ -

    int a = -10;
    int b = +a;//但在负数前面加一个+号还是负数
    printf("%d\n", b);//结果为-10

sizeof

sizeof是操作符,是单目操作符,注意它不是函数

    int a = 10;
    printf("%d\n", sizeof(a));//4
    printf("%d\n", sizeof(int));//4,当它后面跟数据类型时,()不可以省略
    printf("%d\n", sizeof a);//4,后跟变量,()可以省略不写,这也证明了它不是一个函数
    int arr[10] = { 0 };
    printf("%d\n", sizeof(arr));//40 计算的是整个数组的大小,单位是字节
    printf("%d\n", sizeof(arr[0]));//计算数组第一个元素的大小
    printf("%d\n", sizeof(arr) / sizeof(arr[0]));//10 - 数组的元素个数

++和- -

    int a = 10;
    int b = a++;//后置++,先使用,后++
    // b = a; a=a+1;此时先使用a把a赋给b,再对进行自加
    //此时b = 10,a = 11
    int b = ++a;//前置++,先++,后使用
    //先对a进行自加,在使用啊的值赋给b,a=a+1;b=a;
    //这里a,b的值都是11
    int a = 10;
    int b = a--;
    //b=a; a=a-1;
    int b = --a;
    //a = a - 1; b = a;
    printf("%d\n", b);// 9
    printf("%d\n", a);// 9

()强制转换类型

    int a = (int)3.14;
    //int a = int(3.14);错误用法
    printf("%d\n", a);//3
    //3.14 字面浮点数,编译器默认理解为double类型,把它强制转换为int类型

73d8c9be8b2a4960a39693770de0ac9a.png

73d8c9be8b2a4960a39693770de0ac9a.png

&& 逻辑与 - 并且
|| 逻辑或 - 或者
int a = 0;
int b = 0;
if (a && b)
{
printf("hehe\n");
}
int a = 0;
int b = 0;
if (a || b)
{
printf("hehe\n");
}

73d8c9be8b2a4960a39693770de0ac9a.png

三目操作符,针对三个操作数

当exp1为真时,执行exp2;当exp1为假时,执行exp3

int a = 10;
int b = 20;
int r = (a > b ? a : b);

逗号表达式

exp1, exp2, exp3, …expN

逗号表达式就是逗号隔开的一串表达式

逗号表达式的特点是:从左向右依次计算,整个表达式的结果是最后一个表达式的结果

int main()
{
 int a = 10;
int b = 20;
int c = 0;
//       c=8    a=28   表达式的结果为5
int d = (c=a-2, a=b+c, c-3);
printf("%d\n", d);
 return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

前面俩个我们已经有一些了解,分别用在数组和函数上;后俩个在后面的结构体会介绍到

int main()
{
   int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
   int n = 3;
   arr[n] = 20;//[]就是下标引用操作符  arr和3就是[]的操作数
   //a+b 
   return 0;
}
//函数调用操作符()
int Add(int x, int y)
{
  return x+y;
}
int main()
{
   int sum = Add(2, 3);//()就是函数调用操作符,Add,2,3都是()的操作数
   return 0;
}

11. 常见关键字.

73d8c9be8b2a4960a39693770de0ac9a.png

这些关键字有我们常用的已经熟悉的,也有陌生的,不要求全部掌握,有些暂时只需了解有个印象即可,在之后会逐个更新详解

要注意关键字C语言当中本来就存在的,不能自己创建,了解这些关键字避免我们在起变量名时与关键字冲突

简单介绍几个关键字的使用方法,没有介绍到的在后面会更新详细分析

11.1 关键字 typedef.

typedef 顾名思义是类型定义,这里应该理解为类型重命名,结合代码理解

//将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名
typedef 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;
int main()
{
   //观察n1和n2,这两个变量的类型是一样的
   struct Node n1;
   Node n2;
   return 0;
}

11.2 关键字static.

在C语言中:

static是用来修饰变量和函数的

11.2.1static修饰局部变量.

对比俩段代码及运行结果理解

73d8c9be8b2a4960a39693770de0ac9a.png

简单拓展一下计算机中的内存知识,帮助大家理解

内存划分为三个区域,栈区,堆区和静态区;栈区用来存放临时变量,静态区存放全局变量73d8c9be8b2a4960a39693770de0ac9a.png

static修饰局部变量的时候,局部变量出了作用域,它不会再被销毁。本质上,static修饰局部变量的时候,改变了变量的存储位置,影响了变量的生命周期,生命周期变长,当整个程序执行结束后,它的生命周期才结束。

第一段代码当test()函数调用结束后,变量i便被销毁了,再次调用时重新创建;而第二段代码中test()函数中,变量i被static修饰后,函数调用后变量i不会被销毁,当函数再次调用时变量i继上一次的值继续使用。

结论:

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

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

1.2.2 static修饰全局变量.

全局变量是在整个工程中都可以使用的,它具有外部链接属性,可以在多个源文件(.c)中使用,我们在一个工程下的俩个源文件中给出代码帮助理解。

73d8c9be8b2a4960a39693770de0ac9a.png

image.png

static修饰全局变量的时候,这个全局变量的外部链接属性就变成了内部链接属性,其他源文件(.c)就不能再使用到这个全局变量了。

第一个代码可以正常运行,第二个代码在编译的时候会出现连接性错误。

结论:

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

11.2.3 static修饰函数.

函数也是具有外部链接属性的,static修饰函数时与修饰全局变量时有些类似,可以对照着进行理解。

73d8c9be8b2a4960a39693770de0ac9a.png

image.png

一个函数本来具有外部链接属性的,但是被static修饰的时候,外部链接属性就编程了内部链接属性,其他源文件(.c)就无法使用了。

代码1正常,代码2在编译的时候会出现连接性错误.

结论:

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

11.3 关键字register.

registerer修饰变量时,作用时建议将这个变量存放到寄存器中,寄存器时电脑中的存储设备电脑中的存储设备有硬盘内存、高速缓存(cache)、寄存器(集成cpu上),它们处理数据的速度是依次递增的。

73d8c9be8b2a4960a39693770de0ac9a.png

当把数据存储在寄存器时,数据处理的效率会更高

int main()
{
  //寄存器变量
  register int num = 3;//建议: 3存放在寄存器中,只是建议,不是决定
  return 0;
}

12. define 定义常量和宏.

上面介绍常量的时候,我们说define可以定义标识符常量,这里讲它还可以定义

//define定义标识符常量
#define NUM 100
int  main()
{
  printf("%d\n", NUM);
  int n = NUM;
  printf("%d\n", n);
}
//#define 定义宏
//宏是有参数的
#define ADD(x,y)  ((x)+(y))
int main()
{
  int a = 10;
  int b = 20;
  int c = ADD(a, b);
  printf("%d\n", c);
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

13. 指针.

这里在代码部分会穿插讲解这俩个操作符

73d8c9be8b2a4960a39693770de0ac9a.png

用生活中的例子比较,我们为什么可以收到来自不同地方的快递呢?是因为我们所在的地方都有一个坐标地址,通过这个地址便可以知道我们所在;同样的,在计算机中,也有地址的存在,便是指针(地址)。

13.1 内存

内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。

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

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

那么内存单元是如何编号(编址)的呢?

对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);那么32根地址线产生的地址就会是:

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000001

11111111 11111111 11111111 11111111

这里就有2的32次方个地址。

每个地址标识一个字节,那我们就可以给4G的空间进行编址。

73d8c9be8b2a4960a39693770de0ac9a.png

64位电脑一样的方法。

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

取出变量地址如下:

#include <stdio.h>
int main()
{
  int num = 10;
  &num;//取出num的地址
  //注:这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)
  printf("%p\n", &num);//打印地址,%p是以地址的形式打印
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

那地址如何存储,需要定义指针变量;存放指针(地址)的变量就是指针变量。

int num = 10;
int *p;//p为一个整形指针变量
p = &num;

指针的使用实例:

int main()
{
  int a = 10;//向内存申请4个字节,存储10
  //&a;//取地址操作符
  //printf("%p\n", &a);//0x0012ff40
  int* p = &a;
  //p就是指针变量
  *p = 20;//解引用操作符,意思就是通过p中存放的地址,找到p所指向的对象,*p就是p指向的对象
  printf("%d\n", a);//20
  //char ch = 'w';
  //char * pc = &ch;
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

13.2 指针变量的大小

#include<stdio.h>
int main()
{
  //int* p;
  //char* p2;
  //不管是什么类型的指针,都是在创建指针变量
  //指针变量是用来存放地址的
  //指针变量的大小取决于一个地址存放的时候需要大多空间
  //32位机器上的地址:32bit位 - 4byte,所以指针变量的大小是4个字节
  //64位机器上的地址:64bit位 - 8byte,所以指针变量的大小是8个字节
  printf("%zu\n", sizeof(char*));
  printf("%zu\n", sizeof(short*));
  printf("%zu\n", sizeof(int*));
  printf("%zu\n", sizeof(float*));
  printf("%zu\n", sizeof(double*));
  return 0;
}

73d8c9be8b2a4960a39693770de0ac9a.png

14. 结构体.

73d8c9be8b2a4960a39693770de0ac9a.png

变量只能描述单一的信息,是不可以描述复杂类型的,比如:描述学生,学生包含: 名字+年龄+性别+学号 这几项信息;人:名字+年龄+性别+地址+电话;书:书名+作者+出版社+定价+书号;这些都是复杂对象,这里就引入结构体特描述它们。

结构体struct可以把一些单一类型组合在一起,达到描述复杂对象的效果;它具有自定义类型的能力。

//学生(创建一个复杂类型)
struct Stu
{
  //成员
  char name[20];
  int age;
  char sex[10];
  char tele[12];
};
void print(struct Stu* ps)
{                             //通过指针解引用找到对象进行访问
  printf("%s %d %s %s\n", (*ps).name, (*ps).age, (*ps).sex, (*ps).tele);
  //->
  //结构体指针变量->成员名,与上面的效果是一样的
  printf("%s %d %s %s\n", ps->name, ps->age, ps->sex, ps->tele);
}
int main()
{
     //对一个对象的信息进行描述
  struct Stu s = {"zhangsan", 20, "nan", "15596668862"};
                            //结构体对象.成员名
  printf("%s %d %s %s\n", s.name, s.age, s.sex, s.tele);
  print(&s);
  return 0;
}

总结

到这自入门篇C语言的就结束了,简单介绍了一些c语言当中的基本知识点和用法,帮助大家在之后可以看懂一些其他人的代码,方便进行深入学习,提高学习效率和能力;在之后也会陆续更新每个知识点详细的分析,当然我的观点不一定是对的,如果发现有错误的内容,可以在评论区交流,我们可以一起交流进步。

如果这些内容对大家有那么一点帮助,可以三连支持一下,我会把自己的一些观点和学习总结更新在这里,帮助自己也希望可以给大家一些帮助,谢谢!

目录
相关文章
|
2月前
|
安全 编译器 C语言
C++入门1——从C语言到C++的过渡
C++入门1——从C语言到C++的过渡
62 2
|
2月前
|
存储 Java 编译器
初识C语言1——C语言入门介绍
初识C语言1——C语言入门介绍
30 1
|
2月前
|
C语言
回溯入门题,数据所有排列方式(c语言)
回溯入门题,数据所有排列方式(c语言)
|
4月前
|
C语言
C语言------程设设计入门
这篇文章是C语言程序设计的入门教程,涵盖了C程序的实现过程、VC集成开发环境的使用、基本数据类型的使用、格式控制字符的作用,以及通过示例代码演示了如何使用printf()函数输出不同类型的数据。
C语言------程设设计入门
|
5月前
|
存储 Java C语言
【C语言入门】初识C语言:掌握编程的基石
【C语言入门】初识C语言:掌握编程的基石
69 4
【C语言入门】初识C语言:掌握编程的基石
|
4月前
|
NoSQL Java 编译器
C语言从入门到精通该怎样学?
持续学习与实践:编程是一门需要不断学习和实践的技能,要保持对新技术和新知识的敏感性,并持续进行编程实践。
63 1
|
5月前
|
存储 Java 程序员
【C语言入门】C语言入门:探索编程世界的基础概念
【C语言入门】C语言入门:探索编程世界的基础概念
111 2
|
5月前
|
前端开发 C语言 C++
C语言入门02---环境搭建
C语言入门02---环境搭建
|
6月前
|
存储 Web App开发 算法
c语言的简单入门
熟悉c语言(简单入门)
|
6月前
|
JavaScript C语言