【重拾C语言】第一课 初识C语言

本次博客内容来源于鹏哥比特就业课,BV号1q54y1q79w

1、C语言的发展历史:

机器语言——>汇编语言——>B语言——>C语言

2、C语言的国际标准

C89、C90、C99、C11

美国国家标准局 ANSI C

3、创建C语言代码的过程

Step1:创建新项目

48b9246ba2c54441b98ebcd15fb8be90.png Step2:空项目

 82a8ed906d0648d2951f3ccf9b528a7c.png

 Step3:配置新项目51ce78c28319453b9da0549ce7bb3910.png

Step4:解决方案资源管理器——>源文件——>添加——>新建项

9631a458740545d88a02c8e9d9a32475.png

 Step5:C++文件,名称后缀改为.c

aae2bb13bf8a4aaba09638c919a87287.png

 Step6:开始编程!【运行快捷键:Fn+F5】

6d45192344ef412f82cbb32d8544932f.png

 一个工程中可以有多个.c文件,但是每个.c文件只能有一个主函数int main()

4、数据类型

char        //字符数据类型
short       //短整型
int         //整形
long        //长整型
long long   //更长的整形
float       //单精度浮点数
double      //双精度浮点数
注:在C语言中,C语言中没有字符串类型,字符串是存放在字符型数组中的,将字符串作为字符数组来处理的。为了测定字符串的实际长度,C语言规定了一个“字符串结束标志”,以字符'\0'作为结束标志 。
C语言各种数据类型的意义:更方便表示生活中的各种值。

4.1 各种数据类型的大小

77cb1ed7ea02470fb542867f44b59db7.png

 注:C语言标准 sizeof(long)≥sizeof(int)!

5、常量和变量

常量:不变的量

变量:顾名思义,值会改变的量

5.1 变量的定义

int age = 150;
float weight = 45.5f; //注意要有f,因为编译器默认小数类型为double,不加f会导致精度丢失而报错 
char ch = 'w';

 950af34765af4213b0d017c5551ce2bd.png

 5.2 全局变量和局部变量

全局变量:在{}外部定义的变量

局部变量:在{}内部定义的变量

5241a4e14f684a12b14d756703ced3df.png

由此可见当局部变量和全局变量相冲突时,全局变量会被屏蔽,此时起作用的是局部变量。

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

但这样在visual studio上会报错

c69ab447671b4781adc9918e4779dc7c.png

原因:scanf是标准C语言提供的函数,而scanf_s是VS编译器提供的函数。VS认为scanf这个函数不安全

 解决方法:源文件最上边加 

#define _CRT_SECURE_NO_WARNINGS 1

不建议使用scanf_s,因为只有VS编译器可以识别此函数,别的编译器 (如gcc)并无法识别此函数,这样会降低程序的可移植性。

2c937460cade4020a877d618343fbbcb.png

Tips:为了使得每次打开VS后源程序第一行自动添加#define _CRT_SECURE_NO_WARNINGS 1这一行,我们可以用notepad++打开 C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\VC\VCProjectItems\newc++file.cpp文件

40c2a046456549e9b367341d646e820e.png

0b488a9dd4514e4ba91113ddfcf452e9.png

 选择“是”

dfa21009af024a48b3cd6cc4b1b10188.png

然后用ctrl+S保存。

8859baf3ade341e88b321536069c6fe5.png

从此每新建.c文件时第一行都会自动添加 #define _CRT_SECURE_NO_WARNINGS 1

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

作用域 :
作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用
而限定这个名字的可用性的代码范围就是这个名字的作用域。
1. 局部变量的作用域是变量所在的局部范围。
2. 全局变量的作用域是整个工程。
生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
2. 全局变量的生命周期是:整个程序的生命周期。

5.5 常量

C语言中常量有如下类型:
(1)字面常量。如 3,100,3.14等
(2)const修饰的常变量。const修饰的量虽然不可以改变值,但是其本质还是一个变量。
4115c41f19284b14a3448af9169e7290.png

 由此可见常变量是不可以修改的。

9991c613e78c4075a4f5cf51bd935c62.png

由此可见由const修饰的常变量的本质还是变量。const 修饰的常变量在C语言中只是在语法层面限制了变量不能直接被改变,但是本质上还是一个变量的,所以叫常变量。

(3) #define 定义的标识符常量

bcbd9888702f43228d03f95b89d060a4.png

和const对比,可以发现#define定义的是常量

(4)枚举常量

#include<stdio.h>
enum SEX
{
	MALE,
	FEMALE,
	SECERT
};
int main()
{
	enum SEX s1 = MALE;
	printf("%d\n", MALE);
	printf("%d\n", FEMALE);
	printf("%d\n", SECERT);
	return 0;
}

 c11ae71f4bdc479296fda8880deac671.png

注:枚举常量的默认是从0开始,依次向下递增1的 

550d77fb62f345ed9b053cde001b3607.png

变量是可以改的,但是常量本身是不可以被更改的。

7082d612184a43588b9fe1603ec61290.png

6、字符串 转义字符 注释

6.1 字符串 

字符串:由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
#include<stdio.h>

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

87c81c9e2f6948009afbbf8309e5a5b0.png

我们打印一下arr1和arr2的长度

00b6cd18ef3f4417aa188829e39d1640.png

 运行发现,arr1正常输出,但arr2不是正常输出。

下面进行调试。

按Fn+F10,进入调试界面。

53dc4ff55dab416d81e9b40546b03890.png

调试——>监视——>监视1

2e021f9b92b14f2793320d4524533cac.png 按下Fn+F10,一步一步进行调试,观察arr1、arr2.

2966bb14d82041088c2f2927adbbcd89.png

 我们发现arr2比arr1少了一个元素,即“\0”(字符串结束标志),在数值上是0。

因此可以解释arr2错误输出的问题。因为arr2并没有字符结束标志,因此编译器会不停地打印字符和计算长度,由此arr2就输出了“abc烫烫烫烫...”,并且长度是42,可以推测在第43个位置上碰到了\0。

我们在arr2后面加"\0”,或者0,即可正常输出。

f905b37af4074569a5eae946b2542202.png

6.2 转义字符

 转义字符(Escape character):C中定义了一些字母前加"\"来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符意思了。

2870e922037b4e37b598d168c9ea3aa1.png

 常见的转义字符如下:

2b27e1995ca14e29ae5685c0bf9a2934.png

 看下面一段代码,能否打印出我们想要的路径?

#include <stdio.h>
int main()
{
    printf("c:\code\test.c\n");
    return 0; 
}

实际运行结果:

8b2ed92a5ee5484c881f6f3078e2ef4b.png

 这是因为这里的\c和\t被编译器识别为了转义字符。

为了输出正确的路径,我们需要在\c和\t前面再加一个\,以消去转义。

e80546685bb14829953f1510b9e63876.png

转义字符的长度是1,下面看一道常见的大厂笔试题:

//程序输出什么?
#include <stdio.h>
int main()
{
    printf("%d\n", strlen("abcdef"));
    printf("%d\n", strlen("c:\test\628\test.c"));
    return 0;
 }

 运行结果:

e6fd5449df444ab58c183b538792448d.png

解释为什么第二个长度是14:

1c
2:
3\t
4e
5s
6t
7\62
88
9\t
10e
11s
12t
13.
14c

下面看另一个问题:

261106938c274080b01665925247a5e8.png

解释:

\t是转义字符,为水平制表符。 

\54是转义字符,54转化为10进制为44,对应ascii表为 ,(逗号)

\ddd
ddd表示1~3个八进制的数字,将这个八进制数字转化为10进制后,去对应ascii码表寻找其所对应的字符
\xddxdd表示2个十六进制的数字,将这个十六进制数字转化为10进制后,去对应ascii码表寻找其所对应的字符

如果我只想输出一个“,应该怎么编写代码?

看下面的代码是否可行?

//程序输出什么?
#include <stdio.h>
int main()
{
	printf("%s\n", """);
	return 0;
}

我们看一下运行情况

8cd53941915147f78831210229123b26.png

原因:连续输入三个”,编译器会自动将前两个进行配对,因此第三个“编译器认为是多余的。

解决方法:在”""中间的”号之前加\,消去转义。

fa1f3673ce924f6889b7b1b4bbaa9b8d.png

6.3 注释

注释有两种风格:
(1)C语言风格的注释 /*xxxxxx*/
缺陷:不能嵌套注释
(2)C++风格的注释 //xxxxxxxx
可以注释一行也可以注释多行
多行注释的快捷键:ctrl+k+c
取消多行注释的快捷键:ctrl+k+u

7、循环语句

//while循环的实例
#include <stdio.h>
int main()
{
    printf("加入比特\n");
    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; 
}

9、数组

9.1 数组的定义

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

9.2 数组的下标

C语言规定:数组的每个元素都有一个下标,下标是从0开始的。
数组可以通过下标来访问的。
int arr[10] = {0};
//如果数组10个元素,下标的范围是0-9
4cf605f52e0749a68d558e0418fbf566.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; 
}

10、操作符

10.1 算术操作符

+

-
*
/
%取余
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 9;
	float b = 9.0;
	printf("%d\n", a / 2);
	printf("%f\n", b / 2);
	printf("%d\n", a % 2);
	return 0;
}

23f81d4c501243f683b72d976c4c7aff.png

10.2 移位操作符 

>>右移
<<左移

10.3 位操作符

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

10.4 赋值操作符

=赋值
a += 1;a = a + 1;
a -= 1;

a = a - 1;

a *= 2;a = a * 2;
a /= 2;a = a / 2 ;
a &=b;a = a & b;
a ^= b;a = a ^b;
a |= b;a = a | b;
a >>= 1;a = a >> 1;
a <<= 1;a = a << 1;

10.5 单目操作符

(1) !    逻辑反操作

0 表示假,非0就是真

#include<stdio.h>
int main()
{
	int a = 0;
	printf("%d\n", !a);//1

	return 0;
}

6bc4b10aa79740559a4cb91b85e7f245.png

c29d614b36b44b01abb3f3a4d82fe333.png (2) sizeof      操作数的类型长度(以字节为单位)

sizeof是一个操作符,不是函数,用来计算类型或者变量的大小。

#include<stdio.h>
int main()
{
	//sizeof是一个操作符
	//不是函数
	//计算类型或者变量的大小的
	int a = 10;
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof(a));

	return 0;
}

 e9d146aadbce46dd80e3024edd31a377.png

	printf("%d\n", sizeof int );//代码报错!
	printf("%d\n", sizeof a );//代码不报错

用途举例:计算数组元素个数

#include<stdio.h>
int main()
{
	//10*4 = 40 
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));//计算的是数组的总大小,单位是字节
	printf("%d\n", sizeof(arr[0]));//4
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz);

	return 0;
}

99b6f358872c420c848937496b862b80.png

(3) ~ 按位取反

#include<stdio.h>
int main()
{
	int a = 0;

	printf("%d\n", ~a);

	//~ 按位取反

	return 0;
}

 查看结果:

a3d212d033da458caa6c481e46cb3545.png

原因:整数在计算机中以补码的形式存储。int类型是4个字节,int a = 0;表明a=00000000_00000000_00000000_00000000。而printf输出的是原码。对a按位取反得到11111111_11111111_11111111_11111111,其原码为10000000_00000000_00000000_00000001,表示-1,因此输出为-1.

(4)  (类型)       强制类型转换符 

#include<stdio.h>
int main()
{
	//强制类型转换
	int a = (int)3.14;//正确

    int a = 3.14;//报错
	printf("%d\n", a);
	return 0;
}

4be4a44dcfe44814970add3f6d99f88a.png

 (5)  -- ++

#include<stdio.h>
int main()
{


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

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

	int c = 10;
	int d = ++c;//前置++ - 先++,后使用

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

	return 0;
}

51ff918ab09e424ebbdfe0c1b6b64597.png

(6) 关系运算符

>大于
>=大于等于
<小于
<=小于等于
!=判断“不等于”
==  判断“等于”

 (7)  逻辑操作符

&&逻辑与
||逻辑或

0为假,非0为真

(8)  条件操作符

exp1 ? exp2 : exp3
(9)  逗号表达式
exp1, exp2, exp3,......,expN
(10)  下标引用、函数调用和结构成员
[]数组下标
()函数调用
.结构成员
->结构成员

11、常见关键字

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

注:define、include不是关键字,是预处理指令。

C语言提供的关键字
1. C语言提供的,不能自己创建关键字
2. 变量名不能是关键字

auto 自动的,每个局部变量都是auto,可省略

extern 用于声明外部变量

register 寄存器关键字。计算机读取寄存器的速度快,但寄存器空间有限,不建议大量使用。

0e5ee59eb3d54c3e911950a28de8555e.png

 signed 有符号数

unsigned 无符号数

union 联合体

void 空

struct 结构体

static 静态的

11.1 typedef 类型定义

#include<stdio.h>
typedef unsigned int u_int;
int main()
{
	unsigned int a = 1;
	u_int b = 1;
	return 0;
}
//将unsigned int 重命名为u_int, 所以u_int也是一个类型名
//这里 a b的类型是一致的

11.2 static 静态的

在C语言中:
static是用来修饰变量和函数的
1. 修饰局部变量-称为静态局部变量
2. 修饰全局变量-称为静态全局变量
3. 修饰函数-称为静态函数
05a06a4fceb14654991da82c58aaca9b.png

(1)static修饰局部变量:改变了局部变量的生命周期,让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。
//代码1
#include<stdio.h>

void test()
{
	int i = 0;
	i++;
	printf("%d ", i);
}
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		test();
	}
	return 0;
}
//代码2
#include<stdio.h>

void test()
{
	static int i = 0;//static修饰局部变量
	i++;
	printf("%d ", i);
}
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		test();
	}
	return 0;
}

b0a221ed34584571a04d2a446e24c3de.png

6e19677ab91247ec8a60c905e5020dc0.png

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

全局变量,在其他源文件内部可以被使用,是因为全局变量具有外部链接属性,但是被static修饰之后,就变成了内部链接属性,其他源文件就不能链接到这个静态的全局变量了!
 

//代码2
//test1.c
static int year = 2022;

//test2.c
#include<stdio.h>

int main()
{	
	extern int year;
	printf("%d\n", year);
	return 0;
}

6730ae0054aa4da1afdd2ec4631055a6.png

 代码2在编译的时候会出现连接性错误。

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

//代码1
//add.c
int Add(int x, int y) {
    return c+y; }
//test.c
int main()
{
    printf("%d\n", Add(2, 3));
    return 0;
}
//代码2
//add.c
static int Add(int x, int y) {
    return c+y; }
//test.c
int main()
{
    printf("%d\n", Add(2, 3));
    return 0; 
}

代码1正常,代码2出现链接错误。

本质上: static是将函数的外部链接属性变成了内部链接属性!(和static修饰全局变量一样!)
 

12、define定义常量和宏

//define定义标识符常量
#define MAX 1000
//define定义宏
#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; 
}

5516aea93c41416196ff4c7bf75e5eee.png

13、指针

13.1 内存

内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是 1 个字节
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该 内存单元的地
变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。
af6e934b0223406887d9330c03443c32.png

06bad2ba2cbf4385b5dbce10e4a01b01.png

//int main()
//{
//	int a = 10;//a在内存中要分配空间的 - 4个字节
//	printf("%p\n", &a);//%p 专门用来打印地址的
//
//	int * pa = &a;//pa是用来存放地址的,在C语言中pa叫是指针变量
//
//	//* 说明 pa是指针变量
//	//int 说明pa执行的对象是int类型的
//
//	char ch = 'w';
//	char * pc = &ch;
//
//	return 0;
//}

 13.2 指针变量的大小

因为指针变量存放的内容是地址,所以在32位机上指针变量的大小是32位,也就是4个字节;同理,在64位机上是8个字节。

//指针变量的大小取决于地址的大小
int main()
{
    printf("%d\n", sizeof(char *));
    printf("%d\n", sizeof(short *));
    printf("%d\n", sizeof(int *));
    printf("%d\n", sizeof(double *));
    return 0;
 }

5ea70bda02c5476cbe5a3e40d69fd9ae.png

14、结构体 

结构体可以让C语言创建新的类型出来

例如创建一个学生

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

结构体初始化

//初始化结构体信息
struct Stu s = {"张三", 20, "男", "20180101"};
//.为结构成员访问操作符
printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);
//->操作符
struct Stu *ps = &s;
printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps- >id);
.结构体变量.结构体成员
->指针变量->结构体成员
int main()
{
	struct Stu s = {"张三", 20, 85.5};//结构体的创建和初始化
	printf("1: %s %d %lf\n", s.name, s.age, s.score);//结构体变量.成员变量

	struct Stu * ps = &s;
	printf("2: %s %d %lf\n", (*ps).name, (*ps).age, (*ps).score);//可以这么写,但是略微复杂

	printf("3: %s %d %lf\n", ps->name, ps->age, ps->score);

	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值