初识C语言(C语言基础)

基本了解C语言的基本知识,对C语言有一个大概认识。

本文重点:

  • 什么是C语言
  • 第一个C语言程序
  • 数据类型
  • 变量、常量
  • 字符串+转义字符+注释
  • 数组
  • 操作符
  • 常见关键字
  • define 定义常量和宏
  • 选择语句
  • 循环语句
  • 函数
  • 指针
  • 结构体

1. 什么是C语言?

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

尽管C语言提供了许多低级处理的功能,但仍然保持着良好的跨平台特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。

二十世纪八十年代,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为 ANSI C,作为C语言最初的标准。2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的 C11 标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。

计算机语言的发展:低级 ---> 高级

二进制指令 --> 汇编指令 --> B语言 --> C语言

 10001010      ADD(助记符)                高级语言

C语言是面向过程的计算机编程语言,其编译器主要有Clang、GCC、WIN-TC、MSVC、Turbo C等。

C语言是【结构化】的程序设计语言:

  • 顺序结构
  • 选择结构
  • 循环结构

注:编译和编辑的区别。

什么是编译?

2. 第一个C语言程序

#include <stdio.h>

int main() {    //标准的主函数写法
    printf("hehe\n");    //库函数,作用是在屏幕上打印输出指定的信息

    return 0;
}
//解释:
//main函数(主函数)是程序的入口
//一个工程中main函数有且仅有一个

3. 数据类型

在创建一个变量或者常量的时候,必须要指定出相应的数据类型,否则无法给变量分配内存。

3.1 内置数据类型

char         //字符
short        //短整型
int          //整型
long         //长整型
long long    //更长的整型
float        //单精度浮点数
double       //双精度浮点数

%d        //打印整型
%u/%zu    //打印无符号整型/打印sizeof返回的无符号的整型
%c        //打印字符
%s        //打印字符串
%f        //打印float类型数据
%lf       //打印double类型数据

注意:char 也是属于整形家族的,因为字符存储的时候,存储的是 ascii 码值。

存在这么多的类型,其实是为了更加丰富的表达生活中的各种值。

每种类型大小是多少?

sizeof 关键字

作用:利用 sizeof 关键字 可以统计数据类型所占内存的大小

语法:

sizeof (数据类型/变量); / sizeof 变量;
#include <stdio.h>

int main() {
    printf("%d\n", sizeof(char));     //1
    printf("%d\n", sizeof(short));    //2
    printf("%d\n", sizeof(int));      //4
    printf("%d\n", sizeof(long));     //4
    printf("%d\n", sizeof(long long));//8
    printf("%d\n", sizeof(float));    //4
    printf("%d\n", sizeof(double));   //8
    return 0;
}

long(长整型) 在 Windows 为 4 字节,在 Linux 为 4 字节(32位) / 8 字节(64位)。

类型的使用:

char ch = 'w';
int age= 12;
float weight = 111.0f
double height = 178.8;

默认情况下浮点数是 double 类型,在浮点数的末尾加上 f 后 浮点数为 float 类型。 

3.2 自定义数据类型

结构体、枚举、联合

4. 变量、常量

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

有些值是可变的(比如:年龄,体重等)

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

4.1 定义变量的方法

作用:给一段指定的内存空间起名,方便操作这段内存。

语法

数据类型 变量名 = 初始值;

示例: 

int age = 25;
float weight = 45.5f;
char ch = 'w';

标识符(变量、常量)的命名规则

  1. 有意义。
  2. 名字必须是字母、数字、下划线组成。不能有特殊字符,同时不能以数字开头。并且区分大小写。
  3. 变量名不能是关键字。

建议:给标识符命名时,争取做到见名知意的效果,方便自己和他人阅读。

4.2 变量的分类

  • 局部变量:{ }内部定义变量
  • 全局变量:{ }外部定义变量
  • 全局变量,静态变量都是放在静态区,两者不初始化的时候,默认会被初始化为 0。
  • 局部变量是放在栈区,不初始化的时候,默认值是随机值。
#include <stdio.h>

int global = 2023;//全局变量
int main() {
    int local = 1009;//局部变量
    //下面定义的global会不会出问题?
    int global = 2022;
    printf("global = %d\n", global);
    return 0;
}

注意:

  • 在同一个作用范围内,一个变量名只能定义一次,不能重复定义
  • 全局变量和局部变量名字可以相同,采用局部优先原则。
  • 建议不要将全局变量和局部变量的名字写成一样的。

4.3 变量的使用

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

注意:

  • 首行加入 #define _CRT_SECURE_NO_WARNINGS 忽视函数不安全警告。
  • scanf_s() 是VS编译器自己提供的函数,非标准C提供的函数,其他编译器不认识。

技巧:

通过修改 Microsoft Visual Studio > 2019 > Community > Common7 > IDE > VC > VCProjectItems 目录下的 newc++file.cpp 文件可以永久修改 cpp 文件新建后的初始化内容。

方法:

1. 将文件复制在桌面。

2. 修改后替换原文件。

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

作用域

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

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

  • 局部变量的作用域:变量所在的局部范围。
  • 全局变量的作用域:整个项目。

注:使用其他文件的全局变量需要使用 extern 来声明来自外部的符号

extern int a;

extern int Add(int x, int y);

生命周期

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

  • 局部变量的生命周期:进入作用域开始,出作用域结束。
  • 全局变量的生命周期:整个程序的生命周期。

4.5 常量

作用:用于记录程序中不可更改的数据。

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

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

  • 字面常量
  • const 修饰的常量
    • 格式:cosnt 数据类型 常变量名 = 常量值;
    • 通常在变量定义前加关键字 const,表示一个常变量。
  • #define 定义的标识符常量
    • 格式:#define 常量名 常量值
    • 通常在文件上方定义,表示一个常量
  • 枚举常量
//1.字面常量
30;
3.14;
'ww';

//2.const 修饰的常变量
const int a = 10;

//3.#define定义的标识符常量
#define MAX 100

//4.枚举常量
enum Color    //定义枚举类型不开辟空间,创建枚举变量才开辟空间
{
    //枚举常量
    RED,
    GREEN,
    BLUE
};

enum Color r = RED;

注:在C语言中,const 修饰的 a, 本质是变量,但是不能被修改,有了常量的属性,所以叫常变量。

5. 字符与字符串

5.1 字符

作用:字符型变量显示单个字符

语法

char ch = 'a';

注意:

  1. 在显示字符常量时,用单引号将字符括起来,不要用双引号。
  2. 单引号内只能有一个字符,不可以是字符串。
  • 字符变量只占用一个字节
  • 字符变量并不是把字符本身放到内存里存储,而是将对应的 ASCII 码放入到存储单元

5.2 字符串

"abcdefg\n"

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

注:

  • 字符串的结束标志是一个 '\0' 的转义字符。在计算字符串长度的时候 '\0' 是结束标志,不算作字符串内容。
  • EOF(end of file) 是文件的结束标志,值是 -1。
#include <stdio.h>

int main() {
    char arr1[] = "abc";
    char arr2[] = {'a', 'b', 'c'};
    char arr3[] = {'a', 'b', 'c', '\0'};
    printf("%s\n", arr1);
    printf("%s\n", arr2);
    printf("%s\n", arr3);
    printf("%d\n", strlen("abc de"));    // 6
    return 0;
}

5.3 转义字符

转义字符顾名思义就是转变意思。 

作用:用于表示一些不能显示出来的ASCII字符

现阶段我们常用的转义字符有:\n, \\, \t

转义字符释义ASCII 码值(十进制)
\?在书写连续多个问号时使用,防止他们被解析成三字母词063
\'用于表示字符常量 '039
\"用于表示一个字符串内部的双引号034
\\用于表示一个反斜杠,防止它被解释为一个转义序列符092
\a警告字符,蜂鸣007
\b退格符(BS),将当前位置移到前一列008
\f进纸符(FF),将当前位置移到下页开头012
\n换行(LF),将当前位置移到下一行开头010
\r回车(CR),将当前位置移到本行开头013
\t水平制表符(HT)(跳到下一个 TAB 位置)009
\v垂直制表符(VT)011
\0数字 0000
\dddddd 表示 1~3 个八进制的数字。如:\130  X3 位 8 进制
\xdd

dd 表示 2~3 个十六进制数字。如:\x30  0

3 位 16 进制
printf("%c\n", '\130');       // X
printf("%c\n", '\x30');       // 0

三字母词(早期编译器):

  • '??)' ---> ']'
  • '??(' ---> '['
#include <stdio.h>

int main() {
    //问题1:在屏幕上打印一个单引号',怎么做?
    //问题2:在屏幕上打印一个字符串,内容中含有双引号",怎么做?
    printf("%c\n", '\'');
    printf("%s\n", "\"");
    return 0;
}
//测试
#include <stdio.h>

int main() {
    printf("%d\n", strlen("c:\test\628\test.c"));    // 14
    return 0;
}

注:

  • \62 被解析成一个转义字符(8不是8进制数字)
  • Ascii码值的范围是 0 ~ 127,超出该范围将会出错,超过255将会报错。

5.4 注释

作用:在代码中加一些说明和解释,方便自己或其他程序员阅读代码。

注释是写给程序员看的,不是写给电脑看的。

C语言注释方法有两种:

  • 单行注释(C++注释风格)://xxxx

                通常放在一行代码的上方,或者一条语句的结尾,对该行代码说明

                缺陷:不能用于嵌套注释

  • 多行注释(C语言注释风格):/*xxxx*/

                通过放在一段代码的上方,对这段代码做整体说明

                特点:可以注释一行也可以注释多行

提示:编译器在编译代码时,会忽略注释的内容。

6. 选择语句

7. 循环语句

8. 函数

9. 数组

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

9.1 数组的定义

int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//定义一个整型数组,最多存放10个元素
int arr[10] = {1};    //把整型数组的第一个元素初始化为1,其他元素默认初始化为0
int arr[] = {1, 2, 3};

char ch[10] = "hello abc";    //用字符串初始化字符数组

注:

  • 数组声明时必须指定数组的大小。
  • 数组如果初始化,可以不指定数组的大小。 

  • C99标准之前,数组的大小都是用常量或者常量表达式来指定。
  • C99标准之后,支持了变长数组,允许数组的大小是变量,但是这种指定方式的数组是不能初始化的。(VS对C99中的一些语法支持不是很好,不支持变长数组)

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 (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);    // 数组的使用
    }
    printf("\n");
    return 0;
}

10. 操作符

C语言是非常灵活的:C语言提供了非常丰富的操作符,使用起来比较灵活。

10.1 操作符的分类

  • 算术操作符
+   -   *   /   %

 注:

  • 除号两端都是整数的时候,执行的是整数的除法,如果两端有浮点数就执行浮点数的除法。
  • 取模操作符的两个操作数只能是整数。
  • 移位操作符

涉及二进制的运算。

>>   <<
  • 位操作符
%   ^   |
  • 赋值操作符
=   +=   -=   *=   /=   &=   ^=   |=   >>=   <<=
  • 单目操作符

        只有一个操作数的操作符

!            逻辑反操作
-            负值
+            正值
&            取地址
sizeof       操作数的类型长度(以字节为单位)
~            对一个数的二进制按位取反
--           前置、后置--
++           前置、后置++
*            间接访问操作符(解引用操作符)
(类型)        强制类型转换
  • 关系操作符 
>
>=
<
<=
!=            用于测试“不相等”
==            用于测试“相等”
  •  逻辑操作符
&&            逻辑与
||            逻辑或
  •  条件操作符(三目操作符)
exp1 ? exp2 : exp3
  • 逗号表达式
exp1, exp2, exp3, ...expN
  •  下标引用、函数调用和结构成员
[]    ()    .    ->

10.2 操作符的使用

sizeof 操作符的使用 

int a = 10;
printf("%d\n", sizeof(a));    //4
printf("%d\n", sizeof(int));  //4
printf("%d\n", sizeof a);     //4,不能 sizeof int

int arr[10] = {0};
printf("%d\n", sizeof(arr));  //40 计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(arr) / sizeof(arr[0]));    //10 数组的元素个数

前置、后置操作符的使用

int a = 10;
int b = a++;//后置++: 先使用,后++
//int b = a; a = a + 1;

printf("%d\n", b);     //10
printf("%d\n", a);     //11

int a = 10;
int b = ++a;//前置++: 先++,后使用
//a = a + 1; int b = a; 

printf("%d\n", b);     //11
printf("%d\n", a);     //11

 强制类型转换操作符

int a = (int)3.14;
//3.14 字面浮点数,编译器默认理解为double类型

逗号表达式的使用

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

int a = 10;
int b = 20;
int c = 0;
int d = (c = a - 2, a = b + c, c - 3);

下标引用操作符

int arr[10] = {0};
arr[3] = 20;    //[] 就是下标引用操作符,arr 和 3 就是 [] 的操作数

函数调用操作符

int Add(int x, int y) {
    return x + y;
}

int main() {
    int sum = Add(2, 3);//() 就是函数调用操作符,Add、2、3 都是 () 的操作数

    return 0;
}

11. 常见关键字

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

auto(自动变量)  break  case  char  const(常属性)  continue  default  do  double  else  
enum(枚举)  extern(声明外部符号)  float  for  goto(跳转语句)  if  int  long  register(寄存器)
return  short  signed(有符号的)  sizeof  static(静态)  struct(结构体)  switch  
typedef(类型重命名)  union(联合体)  unsigned(无符号的)  void(无,函数返回类型和参数)  
volatile  while

11.1 关键字 typedef

顾名思义就是类型定义,这里应该理解为类型重命名。比如:

typedef unsigned int uint_32;

int main() {
    unsigned int num1 = 0;
    uint_32 num2 = 0;

    return 0;
}

11.2 关键字 static

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

  1. 修饰局部变量 - 称为静态局部变量
  2. 修饰全局变量 - 称为静态全局变量
  3. 修饰函数 - 称为静态函数

1. 修饰局部变量:

局部变量出了作用域不销毁。(本质上,static 修饰局部变量时改变了变量的存储位置,将变量从存放栈区改变成了存放静态区,程序销毁变量才销毁。)

影响了变量的生命周期,和程序的生命周期一样长。

#include <stdio.h>

void test() {
    static int a = 0;
    a++;
    printf("%d ", a);
}

int main() {
    int i = 0;
    for (int i = 0; i < 10; i++) {
        test();
    }
    return 0;
}

注意:static 定义变量在第二次调用时不执行。(在编译期间就创建好了,不参与汇编)

2. 修饰全局变量

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

影响了全局变量的作用域,由整个项目变为了该文件。

3. 修饰函数

函数是具有外部链接属性的。static 修饰函数时 函数的外部链接属性就变成了内部链接属性,其他源文件 (.c) 就不能再使用这个函数。

影响了函数的作用域,由整个项目变为了该文件。

11.3 关键字 register

//寄存器变量
register int num = 3;//建议:3 存放在寄存器中(编译器说了算)

 12. #define 定义常量和宏

define不是关键字,是预处理指令!

//define 定义标识符常量
#define MAX 1000

//define 定义宏,宏完成替换功能
#define ADD(x, y) ((x) + (y))

#include <stdio.h>

int main() {
    int n = MAX;
    int arr[MAX] = {0};

    int sum = ADD(2, 3);
    printf("sum = %d\n", sum);
    
    sum = 10 * ADD(2, 3);
    printf("sum = %d\n", sum);
    
    return 0;
}

#define  ADD(x, y)  ((x) + (y)):

  • ADD: 宏名
  • x, y: 宏的参数,参数是无类型
  • ((x) + (y)): 宏体

13. 指针

13.1 内存

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

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

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

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

int num = 10;
&num;//取地址操作符,取出num的地址
printf("%p\n", &num);

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

int* p = &num;//p 就是指针变量

int* p = &num:

  • int:说明 p 指向的对象是 int 类型的。
  • *:说明 p 是指针变量。

注意:连续声明多个指针。

int *p1, *p2, *p3;

 指针的使用实例:

#include <stdio.h>

int main() {
    int num = 0;
    int* p = &num;
    *p = 20;//解引用操作符,意思就是通过p中存放的地址,找到p所指向的对象,*p就是p指向的对象。
    return 0;
}

 注意:在口头语中 指针 指的是 指针变量。

13.2 指针变量的大小

不管是什么类型的指针,都是在创建指针变量,指针变量是用来存放地址的,指针变量的大小取决于一个地址存放的时候需要多大的空间。

32 位机器上的地址:32 bit 位 - 4 Byte,所以指针变量的大小是 4 个字节

64 位机器上的地址:64 bit 位 - 8 Byte,所以指针变量的大小是 8 个字节

printf("%zu\n", sizeof(char*));

14. 结构体

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

比如描述学生包含:名字+年龄+性别+学号这几项信息。

这里就需要使用结构体来描述了。

例如:

结构体类型的定义

struct Stu {
    //成员
    char name[20];
    int age;
    char sex[10];
    char tele[12];
};

结构体对象的声明和初始化 

struct Stu s = {"zhang", 20, "nan", "1234"};

结构体对象的访问

//结构体对象.成员名
printf("%s %d %s %s", s.name, s.age, s.sex, s.tele);

整体代码

#include <stdio.h>

struct Stu{
    char name[20];
    int age;
    char sex[10];
    char tele[12];
};

void print(struct Stu* ps) {
    printf("%s %d %s %s", (*ps).name, (*ps).age, (*ps).sex, (*ps).tele);

    //结构体指针变量->成员名
    printf("%s %d %s %s", ps->name, ps->age, ps->sex, ps->tele);
}

int main() {
    struct Stu s = {"zhang", 20, "nan", "1234"};

    //结构体对象.成员名
    printf("%s %d %s %s", s.name, s.age, s.sex, s.tele);
    print(&s);
    return 0;
}

 结构体对象访问成员的方式:

  • 结构体对象.成员名
  • 结构体指针变量->成员名

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值