接受平凡,努力出众,承认普通,但拒绝沉沦于平庸。大家好,我是你们的老朋友,小KK。
前言
什么C语言?
数据类型
变量和常量
定义变量的方法
变量的分类
变量的作用域和生命周期
常量
字符串
转义字符
选择语句
循环语句
函数
数组
操作符
常见关键字
#define 定义常量和宏
指针
指针变量的大小
结构体
此博客所用到的代码我存在了gitee,可以看初始C语言: 初始C语言
原本打算是上一年写C语言这个系列的,由于本人比较懒,再加上学校的事比较多,所以就拖到了现在,前段时间是想着不更新这部分内容的,不过总感觉学的不踏实,缺了点什么,
所以打算利用10余天时间把C语言系列更新完,和大家一起学习进步!!!
话不多说,直接开卷(本篇会概述一下C语言的各个语法,后面细讲)
C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台
C语言是一种面向过程的编程语言,与java,c++等面向对象的编程语言有所不同。
char //字符数据类型
short //短整型
int //整形
long //长整形
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
注:C语言中有字符串类型嘛?
C语言中没有字符串类型,C++中有
每种类型的大小
这里我简单拓展下,
bit 比特
byte 字节 =8bit
kb 1024byte
mb 1024kb
gb 1024mb
tb 1024gb
pb 1024tb
想更深入的了解其中的关系和取值范围,可以看我写的计算机组成原理.
生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型等)
有些值是可变的(比如:年龄,体重,薪资).
不变的值,C语言中用常量的概念来表示,变得值C语言中用变量来表示。
int age=150;
float weight=45.5f;
char ch='w';
- 局部变量
- 全局变量
int a = 2022;//全局变量 int b = 2021;//全局变量 int main() { //test1(); //思考一下a等于哪个值? int a = 2023;//局部变量 printf("%d\n", a); printf("%d", b); return 0; }
全局变量:在函数外定义的变量;使用范围:从定义开始到本源文件结束;
局部变量:在一个函数内定义的变量;使用范围:定义该变量的函数内
简单了解
1.使用全局变量会占用更多的内存(因为其生命期长),不过在计算机配置很高的今天,这个不成为什么问题,除非使用的是巨大对象的全局变量,能避免就一定要避免。
2.使用全局变量程序运行时速度更快一些(因为内存不需要再分配),同样现在也快不了多少。
3.全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。
4.局部变量可以和全局变量重名,但是局部变量会屏蔽全局变量。在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。根据使用范围来区分的。
作用域
作用域,程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域.
1.局部变量的作用域:变量所在的局部范围
2.全局变量的作用域:整个工程
生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
1.局部变量的生命周期:进入作用域生命周期开始,出作用域生命周期结束.
2.全局变量的生命周期:整个程序的生命周期
int main() { { int c = 20; } printf("%d", c); return 0; }
C语言中的常量分为以下几种:
- 字面常量
#include
int main() { 3.14;//字面常量 2021; return 0; }
- const修饰的常变量
#include
int main() { const int a=10;//const修饰的常变量 //const修饰的能修改嘛? a=50; return 0; } //结果:不能修改,左值指定const对象
- #define定义的标识符常量
#include
#define MAX 100//标识符常量 int main() { printf("%d\n",MAX); return 0; }
- 枚举常量
enum Sex { //初始化 MALE=5, FEMALE=12, SECRET }; int main() { enum Sex s; //未初始化;从0开始依次增长 printf("%d\n", MALE);//0 printf("%d\n", FEMALE);//1 printf("%d\n", SECRET);//2 //可以直接赋值嘛?:不可以但是可以初始化 MALE = 5;//不可以 //初始化后的值 printf("%d\n", MALE);//5 printf("%d\n", FEMALE);//12 printf("%d\n", SECRET);//13 return 0; }
“hello bit.\n"
这种由双引号引起来的一串字符称为字符串面值,或者简称字符串.
注:字符串的结束标志是一个\0的转义字符.在计算字符串长度的时候\0是结束标志,不算作字符串内容。
int main() { char arr1[] = "bit"; char arr2[] = { 'b','i','t' }; char arr3[] = { 'b','i','t','\0' }; printf("%s\n", arr1); printf("%s\n", arr2); printf("%s\n", arr3); return 0; }
第二个没有\0也就是结束标志,所以会出现"烫烫烫"这些字;
我们来测试一下,字符串长度
a2中没有\0就没有结束字符,所以会出现随机数;
a1数字是5,说明\0不算进字符串内容
我们这里拓展一下,sizeof
sizeof把\0算进字符串长度中,strlen则不算入;
strlen 是一个函数,它用来计算指定字符串 str 的长度,但不包括结束字符(即 null 字符)。其原型如下面的代码所示:
size_t strlen(char const* str);
也正因为 strlen 是一个函数,所以需要进行一次函数调用,调用示例如下面的代码所示:
char sArr[] = "ILOVEC"; /*用strlen()求长度*/ printf("sArr的长度=%d\n", strlen(sArr));
很显然,上面示例代码的运行结果为 6(因为不包括结束字符 null)。这里需要特别注意的是,函数 strlen 返回的是一个类型为 size_t 的值,从而有可能让程序导致意想不到的结果,如下面的示例代码所示:
/*判断一*/ if(strlen(x)>= strlen(y)) { } /*判断二*/ if(strlen(x)- strlen(y)>= 0) { }
从表面上看,上面的两个判断表达式完全相等,但实际情况并非如此。其中,判断表达式一没什么问题,程序也能够完全按照预想的那样工作;但判断表达式二的结果就不一样了,它将永远是真,这是为什么呢?
原因很简单,因为函数 strlen 的返回结果是 size_t 类型(即无符号整型),而 size_t 类型绝不可能是负的。因此,语句“if(strlen(x)-strlen(y)>=0)”将永远为真。
关键字 sizeof 是一个单目运算符,而不是一个函数。与函数 strlen 不同,它的参数可以是数组、指针、类型、对象、函数等,如下面的示例代码所示:char sArr[] = "ILOVEC"; /*用sizeof求长度*/ printf("sArr的长度=%d\n", sizeof(sArr));
相对于函数 strlen,这里的示例代码运行结果为 7(因为它包括结束字符 null)。同时,对 sizeof 而言,因为缓冲区已经用已知字符串进行了初始化,其长度是固定的,所以 sizeof 在编译时计算缓冲区的长度。也正是由于在编译时计算,因此 sizeof 不能用来返回动态分配的内存空间的大小。
假如我们想打印一个目录:c:\code\test.c\n
我们一般会这样写:
int main() { printf("c:\code\test.c\n"); return 0; }
运行结果却是:
这里就不得不提一下转义字符了。转义字符顾名思义就是转变意思。
下面看一些转义字符。我这里只举几个常见的,大家感兴趣可以下去试试
转义字符 释义 \? 在书写连续多个问号时使用,防止他们被解析成三字母词 \' 用于表示字符常量' \“ 用于表示一个字符串内部的双引号 \\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。 \a 警告字符,蜂鸣 \b 退格符 \f 进纸符 \n 换行 \r 回车 \t 水平制表符 \v 垂直制表符 \ddd ddd表示1~3个八进制的数字。 如: \130 X \xdd dd表示2个十六进制数字。 如: \x30 0
int main()
{
int a = 4, b = 6;
printf("%d\n", a);//换行
printf("%d\t%d\n", a, b);//水平制表符
printf("%c\n", '\'');//用于表示字符常量
printf("%s\n", "\"");//用于表示一个字符串内部的双引号
return 0;
}
思考题:
#include
int main() { printf("%d\n", strlen("abcdef"));//6 // \32被解析成一个转义字符 printf("%d\n", strlen("c:\test\328\test.c"));//14 return 0; }
"如果你好好学习,毕业后就能找到好工作,如果你不好好学习,毕业后·就会就种地(家里有况另算)"这就是一种选择
if(判断条件){ 语句块1 }else{ 语句块2 }
#include
int main() { int code = 0; printf("你会好好学习嘛?(1or0):"); scanf("%d", &code); if (code == 1) { printf("毕业后你会得到好offer\n"); } else { printf("毕业后回家种地\n"); } return 0; }
有些事情需要日复一日的去做,比如你想要找到好工作,就要坚持每天去敲代码,假如当你敲到50000行代码时就可以找到好offer了,没到这之前你需要每天都坚持敲,直到到了就可以结束循环了.
C语言中通如何实现循环囊?
- while语句
- for语句
- do...while语句
这里大家只需要知道就行,后期详细讲.
#include
int main() { printf("找到好offer\n"); int line = 0; while (line <= 20000) { line++; printf("我要继续努力敲代码\n"); } if (line > 20000) printf("赢取白富美\n"); return 0; }
函数就是一段封装好的,可以重复使用的代码,它使得我们的程序更加模块化,不需要编写大量重复的代码。
函数可以提前保存起来,并给它起一个独一无二的名字,只要知道它的名字就能使用这段代码。函数还可以接收数据,并根据数据的不同做出不同的操作,最后再把处理结果反馈给我们。#include
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=num1+num2; sum = Add(num1, num2); //例如:盘子=李四(20,蛋炒饭) //输出 printf("sum = %d\,", sum); return 0; }
要存储1-10的数字,怎么存储?
C语言中给了数组的定义:一组相同类型元素的集合
数组定义int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
数组的使用#include
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; }
简单的介绍下,后面详细讲;
算术操作符
+ - * / %
移位操作符
>> <<
位操作符
& ^ |
赋值操作符
= += -= *= /= &= ^= |= >>= <<=
单目操作符
!: 逻辑反操作
—: 负值
+ : 正值
& : 取地址
sizeof: 操作数的类型长度
~ : 对一个数的二进制按位取反
-- : 前置--,后置--
++ : 前置++,后置++
* : 间接访问操作符(解引用操作符)
关系操作符
>
>=
<
<=
!=
==
逻辑操作符
&& 逻辑与
|| 逻辑或
条件操作符
exp1?exp2:exp3
下标引用,函数调用和结构成员
【】() . ->
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 auto :声明自动变量
short :声明短整型变量或函数
int: 声明整型变量或函数
long :声明长整型变量或函数
float:声明浮点型变量或函数
double :声明双精度变量或函数
char :声明字符型变量或函数
struct:声明结构体变量或函数
union:声明共用数据类型
enum :声明枚举类型
typedef:用以给数据类型取别名
const :声明只读变量
unsigned:声明无符号类型变量或函数
signed:声明有符号类型变量或函数
extern:声明变量是在其他文件正声明
register:声明寄存器变量
static :声明静态变量
volatile:说明变量在程序执行中可被隐含地改变
void :声明函数无返回值或无参数,声明无类型指针
if:条件语句
else :条件语句否定分支(与 if 连用)
switch :用于开关语句 case:开关语句分支
for:一种循环语句
do :循环语句的循环体
while :循环语句的循环条件
goto:无条件跳转语句
continue:结束当前循环,开始下一轮循环
break:跳出当前循环
default:开关语句中的“其他”分支
sizeof:计算数据类型长度
return :子程序返回语句(可以带参数,也可不带参数)循环条件关键字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; }
关键字register
寄存器是存储空间,在电脑上一般是集成到CPU上的所和内存是不同的独立存储空间
可以放在寄存器中,运行速度快,但是寄存器容纳空间小,最后变量存到哪还得看编译器如何决定
#include
int main() { register int num = 100; //# //error printf("%d", num); return 0; } 关键字static
在C语言中:
static是用来修饰变量和函数的
1.修饰局部变量—静态局部变量
2.修饰全局变量—静态全局变量
3.修饰函数 静态函数
static修饰局部变量:
改变了变量的生命周期,不影响作用域
#include
试分析test1和test2的区别 void test1() { int a = 1; a++; printf("%d ", a); } void test2() { static int a = 1; a++; printf("%d ", a); } int main() { int i = 0; while (i < 10) { test1(); i++; } printf("\n"); int j = 0; while (j < 10) { test2(); j++; } return 0; } 默认一个全局变量是具有[外部]链接属性的而如果全局变量被static修饰,是的全局变量的外部链接属性变成了内部链接属性,这个时候这个全局变量只能在本源文件内部使用其他源文件无法链接到,也无法使用!!!
define定义常量 #define MUM 100 //define定义宏 #define MAX(x,y) (x>y?x:y) int main() { int a = 10, b = 20; int c = MAX(a, b);//宏定义,把它替换成c=(a>b?a:b) printf("%d\n", c); return 0; }
注:#define和typedef的区别?
#define INT1 int *
typedef int * INT2;
INT1 a1, b1;
INT2 a2, b2;
b1 = &m;
b2 = &n;
因为 INT1 a1, b1; 被宏代换后为: int * a1, b1;即定义的是一个指向int型变量的指针 a1 和一个int型的变量b1.而INT2 a2, b2;表示定义的是两个变量a2和b2,这两个变量的类型都是INT2的,也就是int *的,所以两个都是指向int型变量的指针。
所以两者区别在于,宏定义只是简单的字符串代换,在预处理阶段完成。而typede不是简单的字符串代换,而是可以用来做类型说明符的重命名的,类型的别名可以具有类型定义说明的功能,在编译阶段完成的。
内存
内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的 。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址
变量都有地址,取出变量地址如下:
int main() { int num = 10;//向内存申请4个字节空间,里面存放10 //sizeof(int)==4 printf("%p\n", &num);//打印地址;&取地址操作符 return 0; }
那地址如何存储,需要定义指针变量
指针使用的实例
int main() { int num = 10;//向内存申请4个字节空间,里面存放10 //sizeof(int)==4 //pa=# pa是一个存放地址的变量,这样的变量成为指针变量 int* pa = # printf("%p\n", &num);//打印地址;&_取地址操作符 *pa = 20;//解引用操作符,会修改num的值 printf("%d\n", num);//20 return 0; }
int main() { printf("%d\n", sizeof(char*)); printf("%d\n", sizeof(short*)); printf("%d\n", sizeof(int*)); printf("%d\n", sizeof(double*)); return 0; }
结论:指针大小在32位平台是4个字节,64位平台是8个字节。
结构体是C语言中特别重要的知识点,结构体使得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);
相信经过阅读本篇博客,对C语言有了初步的了解,知道了C语言的大概语法;这样今天的目的就达到啦,后面我们会对其进行详细讲解,大家记得关注哦,最后再三赞支持一波,爱你们