本篇文章将对C语言有初步的介绍
由于是对C语言的初步介绍 所以很多知识点只是提到 后期的文章将对那些知识点进行详细说明
前言
计算机语言: 人与计算机交流的语言
C语言是一门通用的计算机编程语言 广泛用于底层开发
C语言拥有一套国际标准语法(ANSI C)
C语言代码从主函数的第一行开始执行 是C语言的入口
下面写一个C语言程序的HelloWorld
#include<stdio.h>
int main(){
printf("HelloWorld\n"); //HelloWorld
return 0;
}
其中printf是一个库函数用于在屏幕上打印信息 使用printf需要引用头文件 stdio.h
数据类型
数据类型是用来创建变量的 请看下面的代码 其中C语言标准规定sizeof(long) >= sizeof(int) 不同编译器对此有着不一样的内存分配
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
补充: 计算机中的单位
bit位 - 比特位
byte - 字节 - 8bit
kb - 1024byte
mb - 1024kb
gb - 1024mb
tb - 1024gb
pb - 1024tb
变量
先看看两种创建变量的方式
int num1 = 0; //初始化
int num2; //不初始化 不推荐
变量的分类
简单来说
局部变量 - {}内部的叫局部变量 作用域就在括号里
全局变量 - {}外部的叫全局变量 作用域是整个工程
当局部变量和全局变量命名冲突的情况下 局部优先
不过不建议把局部变量和全局变量命名成一样的
当变量在哪里使用 哪里就是它的作用域
extern 声明外部的变量(全局变量)
生命周期是变量的创建与销毁之间的过程
局部变量的生命周期:进入局部范围生命开始 出局部范围生命结束
全局变量的生命周期:就是程序的生命周期
常量
常量分为4种
1.字面常量
3.14;
2.const修饰的常变量 它的值不能被改变 但本质上还是变量
const int num = 10;
3.define定义的标识符常量
#define MAX 1000;
int main(){
int num = Max; //等价于 int num = 1000;
return 0;
}
4.枚举常量 也就是可以一一列举的常量 如果不初始化它的值 默认从0开始依次递增
若初始化其值 就会从初始化的值依次递增
enum Sex{
MALE,
FEMALE
};
enum Sex sex = MALE;
printf("%d\n",MALE); //0
printf("%d\n",FEMALE); //1
字符串
字符串是一串字符 用双引号引起的子串字符 字符串的结束字符是\0
请看如下代码 对于arr1其默认结尾是\0 对于arr2 系统会在内存中往下寻找 直到找到\0为止
strlen是用来统计字符串长度的函数 不会把\0算进去
#include<stdio.h>
int main(){
char arr1[] = "hello";
char arr2[] = {'h','e','l','l','o'};
printf("%s\n",arr1); //hello
printf("%s\n",arr2); //找到\0为止 内存是一块连续的存储空间
printf("%d\n",strlen(arr1)); //5 求长度的时候不包括在里面
return 0;
}
转义字符
常见的转义字符 \t \n 等 其中\ddd 表示三位八进制数字 \xdd 表示两位十六进制数字
请看如下代码 %s是输出字符串 %c是输出字符的占位符
printf("%s\n","c:\\test\\test.c"); // c:\test\test.c
printf("%c\n",'\''); //打印单引号
printf("%c\n",'\130'); //X
printf("%c\n",'\x41'); //A
请看下面的一道题 输出结果是14 \t占一个字符 \32占一个字符(\ddd是八进制 故不能取到8)
int len = strlen("c:\test\328\test.c");
printf("%d\n",len); //14
注释
注释是用来解释代码的 写好注释很重要
//单行注释 C++注释风格
/*
C语言的注释风格 这种注释是有缺陷的 请看下面的代码
*/
//=======================================================
/*
/*
*/
*/
//我们会发现 /* 与 第一个遇到的*/匹配了 这样程序就会报错
初识选择循环语句
请直接看代码 这里只是对它有初步的了解
//选择语句
int input = 0;
scanf("%d",&input);
if(input == 0){
printf("0000\n");
}else{
printf("1111\n");
}
//循环语句
int count = 3;
while(count >= 0){
printf("%d\t",count);
count--;
}
函数
C语言是由函数构成的 函数就是完成一个特定功能的需要的具体步骤的封装
先简单认识一下即可 完成两个数字相加 请看代码
#include<stdio.h>
int add(int num1,int num2){
int sum = num1 + num2;
return sum;
}
int main(){
int num1 = 7;
int num2 = 5;
int sum = add(num1,num2);
printf("%d\n",sum);
return 0;
}
数组
可以存储相同数据类型的一种容器
数组以下标的形式访问
int arr[] = {1,2,3,4,5,6};
char ch[5] = {'c'}; //不完全初始化
操作符
算数操作符 + - * / %
移位操作符 >> <<
请看代码
移动的是二进制位
00000000 00000000 00000000 00000010
左移一位
00000000 00000000 00000000 00000100
变成4
int a = 2;
int b = a << 1; //移动的是二进制位
printf("%d\n",b);
&按位与 |按位或 ^按位异或(后期介绍)
单目操作符(只有一个操作数的操作符) ! & sizeof ~ ++ --等
逻辑运算符 && ||
请看代码
int arr[10] = {0};
printf("%d\n",sizeof(arr)); //40 计算的是数组的总大小
00000000 00000000 00000000 00000000
11111111 11111111 11111111 11111111 (补码)
整数在内存中存储的是补码
对于负数 例如 -1
10000000 00000000 00000000 00000001 (原码) 第一位代表符号位
11111111 11111111 11111111 11111110 (反码) 符号位不变 其余位取反
11111111 11111111 11111111 11111111 (补码) 补码 = 反码 + 1 这里原反补的计算是针对负数的
对于正整数来说 它的原码等于它的补码
int temp = 0;
printf("%d\n",~temp); //-1 按位取反 把所有二进制位的数字 1变成0 0变成1(包括符号位)
int a = 10;
int b = ++a; //前置++ 先++后使用
int c = 10;
int d = c++; //后置++ 先使用后++
printf("%d\n",a); //11
printf("%d\n",b); //11
printf("%d\n",c); //11
printf("%d\n",d); //10
int num1 = (int)3.14; //强制类型转换
printf("%d\n",num1);
三目表达式
int n1 = 10;
int n2 = 20;
int max = n1 > n2 ? n1 : n2;
逗号表达式 以逗号隔开的一个表达式 从左向右依次计算 整个表达的结果是最后的表达式的结果
int temp = (3,5,8+3);
printf("%d\n",temp);
关键字
常见关键字就不举例了 举几个相对陌生的
auto 每个局部变量前面都默认存在 通常省略
extern 用来申明外部符号的
register 寄存器关键字 建议此变量保存在寄存器中
register int num = 10;
补充:
寄存器 高速缓存 内存 硬盘 网盘 越往下速度越慢 但内存越大
大量频繁被使用的数据 建议放在寄存器中 访问速度很快
define include 不是关键字 是预处理指令
关于typedef 可以将类型重命名 请看代码
#include<stdio.h>
typedef unsigned int u_int; //类型重命名
int main(){
u_int num = 10;
printf("%d\n",num); //10
return 0;
}
关于static关键字
static修饰局部变量 改变了局部变量的生命周期(本质上改变了变量的存储类型)
在内存中 栈区里存放局部变量 函数的参数等 堆区用来动态内存分配 静态区存放全局变量与static修饰的变量 请看下面代码
void test(){
static int a = 0;
a++;
printf("%d\n",a); // 1 2 3 4
}
int main(){
int n = 0;
while(n <= 3){
test();
n++;
}
return 0;
}
补充:
static 修饰的全局变量 使得这个全局变量只能在自己所在的源文件中使用
全局变量作用在整个工程中 在其他源文件内部也可以被使用 是因为全局变量具有外部链接属性
而被static修饰之后 就变成内部链接属性了 其他源文件就不能链接到这个静态的全局变量了
同样的 static 修饰的函数 使得这个函数不能再别的源文件中使用
关于define
define是一个预处理指令
define 本质上就是字符串的替换
define定义符号
#define MAX 1000
int main(){
printf("%d\n",MAX); //1000
return 0;
}
define定义宏 请看 跟我们预想的结果不一样 是因为宏定义直接进行字符串的替换
使得原式等价于4*2+3 结果就是11了
#define ADD(X,Y) X+Y
int main(){
printf("%d\n",4*ADD(2,3)); //11
return 0;
}
初识指针
关于内存
32位机器 - 32根地址线 - 物理线 - 有正负电信号 - 电信号转换为数字信号 - 01组成的二进制序列
产生2^32中内存编号 一个内存编号对应一个内存单元
最终一个内存单元 规定取1个字节大小
指针变量就是为了存放地址的 *pa用来进行解引用操作 而64位机器上 相当于8个字节 故无论什么类型的指针 都是8个字节大小
int a = 10;
printf("%p\n",&a);
int* pa = &a; //指针变量是存放地址的
*pa = 20; //解引用
printf("%d\n",a); //20
printf("%d\n",sizeof(int*)); //8
printf("%d\n",sizeof(char*)); //8
printf("%d\n",sizeof(long*)); //8
printf("%d\n",sizeof(double*)); //8
初识结构体
结构体可以让C语言创造新的类型出来 请看代码
#include<stdio.h>
struct Student {
char name[20];
int age;
};
int main(){
struct Student stu1 = {"张三",20};
printf("%s\n",stu1.name); //张三
printf("%d\n",stu1.age); //20
struct Student * ps = &stu1;
ps->age = 22; //相当于 (*ps).age = 22 ->的使用方式左边是结构体的指针
printf("%d\n",stu1.age);
return 0;
}