1.初识c语言

什么是c语言

c语言是一门通用计算机编程语言,广泛应用于底层开发

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

其编译器主要有Clang(苹果公司开发),GCC(开源并在linux下使用),WIN-TC,SUBLIME,MSVC(VS),Turbo等。

  1. 底层开发
    • 底层开发是指系统的后台和网络的基端,也可以理解成最接近于硬件的开发。
  2. 计算机编程语言
    • 人与计算机沟通的语言
  3. 计算机语言的发展
    • 从低级(机器语言100010)----->高级(汇编语言ADD SUB MOV Jump,c语言等)
  4. c语言的语法规则(国际标准)
    • ANSIC(c语言最初的标准)----->K&R----->C89/C90----->C98(常用)C99…C11…
    • C11标准于2011年由国际化组织(ISO)和国际电工委员会(IEC)发布,是c语言第三个官方的标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。

第一个c语言程序

//F10在编译器中可逐步调试
//std - 标准
//i - input 输入
//o - output 输出
//标准输入输出头文件
#include<stdio.h>
//main函数,主函数
//main函数是程序的入口,有且仅有一个
//int 返回类型整型
int main(){
 //函数体(大括号内部)
 printf("Hello World!");
 return 0;
}
//c语言中有一个约定:
//返回0表示正常返回
//返回的是非0,则表示异常返回

数据类型

我们编程的目的是为了解决实际问题 。而生活中有各种各样的数据,每种都有对应的数据类型,因此c语言才设计了各种数据类型来方便表达生活中的各种值。

  • 数据类型:
char        //字符数据类型
short       //短整型
int         //整型
long        //长整型
long long   //更长的整型
float       //单精度浮点型
double      //双精度浮点型
  • 每种数据类型的大小是多少?
    • 首先,计算机中衡量数据的基本单位(二进制)

    • 其次,用sizeof()来计算它们的大小

bit位byte字节KBMBGBTBPB
二进制位数1byte = 8bit1KB = 1024byte1MB = 1024KB1GB = 1024MB1TB = 1024GB1PB = 1024TB
#include<stdio.h>

int main(){                         // 结果(byte)
  printf("%d\n",sizeof(char));      // 1  
  printf("%d\n",sizeof(short));	    // 2
  printf("%d\n",sizeof(int));       // 4
  printf("%d\n",sizeof(long));      // 4  
  //满足(sizeof(long) >= sizeof(int))即可
  printf("%d\n",sizeof(long long)); // 8
  printf("%d\n",sizeof(float));     // 4
  printf("%d\n",sizeof(double));    // 8
  
  return 0;
}
  • 为什么会出现这么多类型?
    • 数据类型决定了开辟内存空间的大小,因此多种类型出现是为了让我们灵活的选用适当的类型,保证空间的利用率。
  • 类型的使用:
short age = 20;
double salary = 12000.6;
char ch = 'A'
int weight = 120;

变量与常量

生活中有些值是会变的:年龄、体重等。 ---->变量

而有些值则是不会变的:三角函数值,π,血型等。 ---->常量

变量

变量的定义
//类型  变量名 = 赋值
int age = 20;
//当我们使用浮点数时,120.3默认为double类型,所以使用float类型,则需要写为120.3f
float weight = 120.3f;
变量的命名

尽量使变量名有意义

  • 只能由字母(包括大小写)、数字和下划线(_)组成
  • 不能以数字开头
  • 长度不能超过63个字符
  • 变量名中区分大小写
  • 变量名不能使用关键字
变量的分类
  • 局部变量:即在一个函数内部定义的变量,只在本函数范围内有效。

  • 全局变量:即从定义变量的位置到本源文件结束都有效。

#include<stdio.h>
//在main函数大括号外定义的叫全局变量
extern int a; //声明外部符号(另一个文件定义)
int num = 100; 
int main(){
  //在大括号内部定义的叫局部变量
  //当全局和局部变量名冲突时,局部变量优先
  int num = 10;
  printf("%d\n",num);
  
  return 0; 
}
变量的使用
//求两个整数相加
#include<stdio.h>
int main(){
  int num1 = 0; //初始化
  int num2 = 0;
  //输入两个数字
  scanf("%d %d",&num1,&num2);
  //相加
  sum = num1 + num2;
  //输出
  printf("%d\n",sum);
  return 0;
}
  • 当VS2019中使用scanf报错时,可以打开newc++file.cpp文件,在里面添加
#define_CRT_SECURE_NO_WARNINGS
  • 如果直接修改时保存不了,可以拷贝到桌面一份,然后再修改,最后将原文件替换即可。
  • scanf在一定程度上来说是不安全的,因为它不会检测输入是否合理,而scanf_s则是VS2019自带的输入方式,虽然会更安全但不适用于其它编译器。
变量的作用域和生命周期

作用域

作用域是程序设计概念,通常来说,一段程序中所用到的名字并不总是有效/可用的,而限定这个名字的可用性代码范围就是这个名字的作用域。

  • 局部变量的作用域是变量所在的局部范围
  • 全局变量的作用域是整个工程

生命周期

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

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

常量

常量的分类
  • 字面常量:直接输入到程序中的值。
  • const修饰的常变量:本质还是变量,但其值无法被更新/修改(拥有常属性)。
  • 用#define定义的标识符常量:也称符号常量,在使用之前必须先定义,属于指令的一部分,不可修改
  • 枚举常量:依旧属于常量,不可以被更新/修改。
常量的定义
#include<stdio.h>

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

//4. 枚举常量
//生活中有很多东西是可以一一列举的
//例如:性别 - 男 女 保密  三原色 - R G B
//C语言支持我们创建枚举类型
//enum 是枚举的关键字
enum Sex{
  //枚举类型中列举出的可能取值都是枚举常量
  //而每个枚举常量都对应了一个默认值(默认从0开始依次递增,可以自定义初始化的值,但无法修改)
  MALE = 4, // 0  // 4
  FEMALE, // 1  // 5
  SECRET // 2  // 6
};

int main(){
  
  //1. 字面常量
  //30 整型
  //3.14 浮点型
  //"adsfd" 字符串...
  
  //2. const修饰的常变量
  const int num = 100;
  int arr1[num]//err 可以证明常变量本身依旧是常量
  //C99之前,不允许数组的大小使用变量指定
  int n = 10;
  int arr2[n];//error
  //C99标准引入了变长数组的概念即可使用
  
  //3. #define定义的标识符常量
  int a = MAX;
  int arr3[MAX];//correct
  
  //4. 枚举常量
  enum Sex s1 = SECRET;
  enum Sex s2 = FEMALE;
   
  return 0;
}

字符串 转义字符 注释

字符串

"Hello World!\n"

这种由双引号引起来的一串字符称为字符串的字面值,或者简称字符串。

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

#include<stdio.h>
#include<string.h>

int main(){
 
 char arr1[] = "abcdef";
 char arr2[] = {'a','b','c','d','e','f'};
 printf("%s\n",arr1); //abcdef
 printf("%s\n",arr2); //乱码
 
 //strlen是一个库函数,用来求[字符串]的长度
 //求出的结果为\0之前出现的字符个数
 printf("%d\n",strlen(arr1)); // 6
 printf("%d\n",strlen(arr2)); //不确定
 printf("%d\n",strlen("abc\0def")); // 3
 
 return 0;
}

在这里插入图片描述

从上图我们可以看出,打印字符串时,只有遇到\0时才会停止,否则就会一直打印,出现一堆乱码
在这里插入图片描述

如果添加上\0在arr2后面,则会恢复正常。因此我们应该重视字符串的结束标志\0。

在这里插入图片描述

转义字符

使用 \ + 字符 将原有字符的意义转变成新的含义

例如:我们打印一串文件路径"C:\test\code\test.c"

#include<stdio.h>
int main(){
  printf("C:\code\test.c");
  //打印结果:C:code    est.c
  
  return 0;
}

c语言中的一些转义字符

转义字符意义ASCII码值(十进制)
\a响铃(BEL)007
\b退格(BS) ,将当前位置移到前一列008
\f换页(FF),将当前位置移到下页开头012
\n换行(LF) ,将当前位置移到下一行(不一定到行首)010
\r回车(CR) ,将当前位置移到本行开头013
\t水平制表(HT) (跳到下一个TAB位置)009
\v垂直制表(VT)011
\ \代表一个反斜线字符’‘’,防止它被解释成一个转义序列符092
代表一个单引号(撇号)字符039
"代表一个双引号字符(字符串内部)034
?在书写连续多个问号时使用,防止它们被解析成三字母词063
\0空字符(NUL)000
\ddd1到3位八进制数所代表的任意字符三位八进制
\xhh十六进制所代表的任意字符十六进制
#include<stdio.h>
int main(){
  
  //   \?的用法
  //避免多重问号构成三字母词
  //三字母词 ??) -> ]
  printf("(are you ok??)\n"); //打印结果:(are you ok]
  //修改内容使得它不可能构成三字母词
  printf("(are you ok\?\?)\n"); //打印结果:(are you ok??)
  
  //   \'和\"的用法
  //当我们想打印单引号或双引号时
  printf("%c\n",'\'');
  printf("%c\n","abc\"");
  
  //   \\的用法
  //让\不被解析为转义字符里的\ 而是一个普通的\
  printf("C:\\code\\test.c"); //打印结果:C:\code\test.c
  
  //   \ddd的用法
  //三位八进制数
  printf("%c\n",'\130'); //打印结果:X(ASCII码值为88)
  
  //   \xhh的用法
  //printf("%c\n",'\x30'); //打印结果:0(ASCII码值为48)
  
  return 0;
}

延伸:由上面的表格对于换行\n和回车\r的解释可知:

  • \n 将当前位置移到下一行(不一定到行首)
  • \r 将当前位置移到本行开头
  • 键盘上的Enter回车键实际是由\r\n 共同构成的

笔试题:

//程序输出什么?
#include <stdio.h>
#include<string.h> 
int main()
{
    printf("%d\n", strlen("abcdef"));
    // \62被解析成一个转义字符
    printf("%d\n", strlen("c:\test\628\test.c"));
    //c : \t e s t \62 8 \t e s t . c
    return 0; 
}
  • 分别输出6和14,注意转义字符为一个字符即可。

注释

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

代码中有些代码比较难懂,可以加一下注释文字

举例:

#include <stdio.h>
int Add(int x, int y) {
    return x+y; 
}
/*C语言风格注释
int Sub(int x, int y)
{
    return x-y;
}
*/
int main()
{
    //C++注释风格
    //int a = 10;
    //调用Add函数,完成加法
    printf("%d\n", Add(1, 2));
    return 0; 
}

注释有两种风格:

  • C语言风格的注释 /xxxxxx/
    • 缺陷:不能嵌套注释
  • C++风格的注释 //xxxxxxxx
    • 可以注释一行也可以注释多行

选择语句

生活中总会面临很多选择,当然也会得到不一样的结果,那我们用代码怎么实现呢?

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

循环语句

生活中还会存在持续做一件事的时候,我们称作循环。C语言中如何实现循环呢?

  • while语句
//while循环的实例
#include <stdio.h>
int main()
{
    int line = 0;
    while(line<=20000)//循环判断条件
    {
        line++;
        printf("我要继续努力敲代码\n");
    }
    if(line>20000)
        printf("好offer\n");
    return 0; }
  • for语句(后面详解)
  • do … while语句(后面详解)

函数

日常生活中我们会有很多种不同的行为方式,我们可以将这些方式封装成函数的形式,方便理解和使用。

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

//上述代码,写成函数如下:
#include <stdio.h>
//int为返回值类型
int Add(int x, int y) { //函数形参为x,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; 
}
  • 函数的特点就是简化代码,代码复用。

数组

当我们要对一些用类型的数据进行存储时应该怎么办呢?

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

数组定义

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

数组的下标

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

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

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

在这里插入图片描述

数组的使用

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

操作符

简单介绍c语言中的一些操作符

算术操作符

+   -   *   /   %
  • 跟数学运算差不多
  • %取余操作符,可以获得两数相除的余数。

移位操作符

>>   <<
  • 数据在计算机中存储为二进制形式。
  • ’ >> ’ 右移操作符,将整体二进制数右移。
  • ’ << ’ 左移操作符,将整体二进制数左移。

位操作符

&   ^   |
  • 对二进制的每一位操作,分别为与、非、或,与逻辑运算类似,因为二进制只有0和1。
  • 举例:
10          //十进制
1010        //二进制
4           //十进制
0100        //二进制
  
//进行&运算(全1为1,其余为0)
1010
0100
0000 ->     //十进制结果为0

//进行||运算(全0为0,其余为1)  
1010
0100
1110        //十进制结果为14

赋值操作符

=   +=   -=   *=   /=   &=   ^=   |=   >>=   <<=
  • 左值 = 右值,将右值赋值给左值。
  • 后面的都为复合操作符,简单演示效果如下:
//将a先加10然后赋值给a
a += 10;  ->  a = a + 10;

单目操作符

!           //逻辑反操作
-           //负值
+           //正值
&           //取地址
sizeof      //操作数的类型长度(以字节为单位)
~           //对一个数的二进制按位取反
--          //前置、后置--
++          //前置、后置++
*           //间接访问操作符(解引用操作符) 
(类型)      //强制类型转换
  • 简单了解有哪些单目操作符即可,它们都只有一个操作数。

关系操作符

>
>=
<
<=
!=   	//用于测试“不相等”
==      //用于测试“相等”
  • 用于判断两边的内容。

逻辑操作符

&&     		//逻辑与
||          //逻辑或
  • 两边表达式进行逻辑与、或后判断。
  • 例如:
// 我的年龄小于20岁并且大于10岁
(age > 10) && (age < 20) 

条件操作符

exp1 ? exp2 : exp3
  • 这是一个三目操作符,一共有三个操作数。
  • 用法如下:
//如果a>b,该表达式的结果为a;而a<=b,该表达式的结果为b。用来得到ab中的最大值。
(a>b)?a:b;

逗号表达式

exp1, exp2, exp3, …expN
  • 逗号表达式是由左向右依次计算。
  • 结果为最后一个表达式的值。

下标引用、函数调用和结构成员

[]   ()   .   ->
  • []常用在数组,()可用在函数调用时。
  • 后面两个用于使用结构体成员。(后续介绍)

常见关键字

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

这里浅浅介绍几个关键字

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

static

在C语言中: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(); //1 1 1 1 1 1 1 1 1 1
    }
    return 0; 
}

//代码2
#include <stdio.h>
void test()
{
    //static修饰局部变量
    static int i = 0;
    i++;
    printf("%d ", i);
}
int main()
{
  	int i = 0;
    for(i=0; i<10; i++)
    {
        test(); //1 2 3 4 5 6 7 8 9 10
    }
    return 0; 
}
  • 对比代码1和代码2的效果理解static修饰局部变量的意义。
  • 代码1输出i = 1结果一直未改变,而代码2输出的结果每次输出都会再加1。
  • 证明static修饰的局部变量只会在第一次进行初始化,然后保存上次函数调用时该变量的值。
修饰全局变量
//代码1
//add.c
int g_val = 2018;
//test.c
int main()
{
    printf("%d\n", g_val);
    return 0; 
}

//代码2
//add.c
static int g_val = 2018;
//test.c
int main()
{
    printf("%d\n", g_val);
    return 0; 
}
  • 代码1正常,代码2在编译的时候会出现连接性错误。
  • 因为一个全局变量被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修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。

#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; 
}
  • 定义标识符常量时可以理解为标识符是常量的符号,如上面所示:NUM就是10的符号。
  • 定义宏时,可以理解为替换,如上面所示:把把x替换成1,把y替换成2。替换就是严格替换,所以定义宏的时候要加很多括号,避免出现一些问题。

指针

内存

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

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

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

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

取出变量地址如下:

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

打印结果如下:

在这里插入图片描述

  • 上面即为打印出的第一个字节的地址(较小的地址),形式为十六进制。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值