初识C语言

1、前言

        大家好,我是Lucas,很高兴能融入社区这个大家庭,希望我们能够一起学习一起加油!我编程的目标是能够成为一名大佬。通过学习与实践相互结合,来增强自己敲代码的能力。我打算每周要学习40+小时,来快速强化我的编程能力,大厂IT公司(百度阿里美团腾讯db字节头条去哪儿25w以上)。

38*3=114

2、什么是C语言

        C语言是任何计算机交流的一种计算机语言,广泛应用于底层开发。C语言是一门面向过程的计算机编程语言。

3、数据类型

1Byte = 8bit

4、变量、常量

C语言中不变的值用 常量的概念来表示,变的值用 变量来表示
int age = 150;
float weight = 45.5f;
char ch = 'w';

//55.5  小数默认是double类型的
//55.5f  这个时候就是float类型
  • 只能由字母(包括大写和小写)、数字和下划线( _ )组成。
  • 不能以数字开头。 长度不能超过63个字符。
  • 变量名中区分大小写的。
  • 变量名不能使用关键字。
  • 变量名要有意义
#include <stdio.h>
int global = 2019;//全局变量
int main()
{
    int local = 2018;//局部变量
    //下面定义的global会不会有问题?
    int global = 2020;//局部变量
    printf("global = %d\n", global);
    return 0;
}
//上面的局部变量global变量的定义其实没有什么问题的!
//当局部变量和全局变量同名的时候,局部变量优先使用。

//%c - 字符
//%d - 整型
//%s - 字符串
//%f - float
//%lf - double
//%p - 地址的打印

作用域

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

1. 局部变量的作用域是变量所在的局部范围。

2. 全局变量的作用域是整个工程。

//add.c
//全局变量
int g_val = 203
//test.c
//需要声明外部符号
extern int g_val

int main(){
    printf("%d",g_val);

    return 0;
}

生命周期

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

1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。

2. 全局变量的生命周期是:整个程序的生命周期。

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

  1. 字面常量  ('a'-字符,“asdf”-字符串)
  2. const 修饰的常变量
  3. #define 定义的标识符常量
  4. 枚举常量
#include <stdio.h>
//举例
enum Sex
{
 MALE,
 FEMALE,
 SECRET
};
//括号中的MALE,FEMALE,SECRET是枚举常量
int main()
{
    //字面常量演示
    3.14;//字面常量
    1000;//字面常量
    
    //const 修饰的常变量 具有常属性但本质还是变量
    const float pai = 3.14f;   //这里的pai是const修饰的常变量
    pai = 5.14;//是不能直接修改的!
    
//#define的标识符常量 演示
 #define MAX 100
    printf("max = %d\n", MAX);
    
    //枚举常量演示
    printf("%d\n", MALE);
    printf("%d\n", FEMALE);
    printf("%d\n", SECRET);
    //注:枚举常量的默认是从0开始,依次向下递增1的
    return 0;
}

 static修饰变量

 1. static修饰变量

   a. 函数中局部变量:

      声明周期延长:该变量不随函数结束而结束

      初始化:只在第一次调用该函数时进行初始化

      记忆性:后序调用时,该变量使用前一次函数调用完成之后保存的值

      存储位置:不会存储在栈上,放在数据段

   b. 全局变量

     改变该变量的链接属性,让该变量具有文件作用域,即只能在当前文件中使用

   c. 修饰变量时,没有被初始化时会被自动初始化为0

  2. static修饰函数

   改变该函数的链接属性,让该函数具有文件作用域,即只能在当前文件中使用

5、字符串+转义字符+注释

1)字符串

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

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

arr2没有用\0结束,所以打印时会一直打印直到遇到\0

char ch1[] = {'a','b'};
int len = strlen(ch1);
//strlen是库函数,用来求字符串长度,就是从给定地址向后数字符,直到遇到\0结束,\0不统计在内

2)转义字符

转义字符释义
\?在书写连续多个问号时使用,防止他们被解析成三字母词
\'用于表示字符常量'
\“用于表示一个字符串内部的双引号
\\用于表示一个反斜杠,防止它被解释为一个转义序列符。
\a警告字符,蜂鸣
\b退格符
\f进纸符
\n换行
\r回车
\t水平制表符
\v垂直制表符
\dddd d d表示1~3个八进制的数字。 如: \130 表示字符X
\xddd d表示2个十六进制数字。 如: \x30 表示字符0

3)注释

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

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

注释有两种风格:

  • C语言风格的注释 /*xxxxxx*/

        缺陷:不能嵌套注释

  • C++风格的注释 //xxxxxxxx

        可以注释一行也可以注释多行

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

6、分支和循环

C语句可分为以下五类:

  1.  表达式语句
  2. 函数调用语句
  3. 控制语句
  4. 复合语句
  5. 空语句

        控制语句用于控制程序的执行流程,以实现程序的各种结构方式(C语言支持三种结构:顺序结构、选 择结构、循环结构),它们由特定的语句定义符组成,C语言有九种控制语句。

可分成以下三类:

  1. 条件判断语句也叫分支语句:if语句、switch语句;
  2. 循环执行语句:do while语句、while语句、for语句;
  3. 转向语句:break语句、goto语句、continue语句、return语句。

1)分支(选择)

#include <stdio.h>
//代码1
int main()
{
 int age = 0;
    scanf("%d", &age);
    if(age<18)
   {
        printf("未成年\n");
   }
}

//代码3
#include <stdio.h>
int main()
{
 int age = 0;
    scanf("%d", &age);
    if(age<18)
   {
        printf("少年\n");
   }
    else if(age>=18 && age<30)
   {
        printf("青年\n");
   }
    else if(age>=30 && age<50)
   {
        printf("中年\n");
   }
    else if(age>=50 && age<80)
   {
        printf("老年\n");
   }
    else
   {
        printf("老寿星\n");
   }
    
}

如果表达式的结果为真,则语句执行。

在C语言中如何表示真假? 0表示假,非0表示真。

#include <stdio.h>
int main()
{
    if(表达式)
   {
        语句列表1;
   }
    else
   {
        语句列表2;
   }
    return 0;
}

2)循环

  1. while
  2. for
  3. do while

7、函数

维基百科中对函数的定义:子程序

  • 在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组 成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。
  • 一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软 件库。

1)库函数

        我们在开发的过程中每个程序员都可能用的到, 为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员 进行软件开发。

cplusplus.com/reference/icon-default.png?t=N7T8https://cplusplus.com/reference/

C语言常用的库函数都有:

  1. IO函数
  2. 字符串操作函数
  3. 字符操作函数
  4. 内存操作函数
  5. 时间/日期函数
  6. 数学函数
  7. 其他库函数

参考手册:

cppreference.comicon-default.png?t=N7T8https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5

2)自定义函数

函数的组成:

ret_type fun_name(para1, * )
{
 statement;//语句项
}
ret_type 返回类型
fun_name 函数名
para1    函数参数

3)函数的参数

实际参数(实参):

        真实传给函数的参数,叫实参。 实参可以是:常量、变量、表达式、函数等。 无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

形式参数(形参):

        形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内 存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数 中有效。

形参实例化之后其实相当于实参的一份临时拷贝。

8、数组

        一组相同类型元素的集合。

定义:

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//定义一个整型数组,最多10个元素
//数组10个元素,下标的范围是0~9

9、操作符

1)操作符分类

  1. 算术操作符
  2. 移位操作符
  3. 位操作符
  4. 赋值操作符
  5. 单目操作符
  6. 关系操作符
  7. 逻辑操作符
  8. 条件操作符
  9. 逗号表达式
  10. 下标引用、函数调用和结构成员

2)算术操作符

+    -   *   /   %
  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数
  2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。

3)移位操作符

<< 左移操作符
>> 右移操作符
//移位操作符的操作数只能是整数。

4)位操作符

& //按位与
| //按位或
^ //按位异或
//他们的操作数必须是整数。

5)赋值操作符

int weight = 120;//体重
weight = 89;//不满意就赋值

复合赋值符:

+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=

6)单目操作符

        只有一个操作数

  • !              逻辑反操作
  • -              负值
  • +             正值
  • &             取地址
  • sizeof      操作数的类型长度(以字节为单位)
  • ~             对一个数的二进制按位取反
  • --             前置、后置--
  • ++           前置、后置++
  • *              间接访问操作符(解引用操作符)
  • (类型)      强制类型转换

sizeof和数组

#include <stdio.h>
void test1(int arr[])
{
 printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
 printf("%d\n", sizeof(ch));//(4)
}

//sizeof是一个操作符
int main()
{
 int arr[10] = {0};
 char ch[10] = {0};
 printf("%d\n", sizeof(arr));//(1)
 printf("%d\n", sizeof(ch));//(3)
 test1(arr);
 test2(ch);
 return 0;
}

//(1)、(2)两个地方分别输出多少?
//(3)、(4)两个地方分别输出多少?
//前置++和--
#include <stdio.h>
int main()
{
    int a = 10;
    int x = ++a;
    //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
    int y = --a;
    //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
    return 0;
}
//后置++和--
#include <stdio.h>
int main()
{
    int a = 10;
    int x = a++;
    //先对a先使用,再增加,这样x的值是10;之后a变成11;
    int y = a--;
    //先对a先使用,再自减,这样y的值是11;之后a变成10;
    return 0;
}

7)关系操作符

>
>=
<
<=
!=   用于测试“不相等”
==   用于测试“相等”

8)逻辑操作符

&     逻辑与
||    逻辑或

区分逻辑与和按位与
区分逻辑或和按位或

1&2----->0
1&&2---->1
1|2----->3
1||2---->1

9)条件操作符

exp1 ? exp2 : exp3    //三目操作符
 真     执行  不执行
 假    不执行  执行
m = ( a > b ? a , b )

10)逗号表达式

exp1, exp2, exp3, …expN

        逗号表达式,就是用逗号隔开的多个表达式。 逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?
//代码2
if (a =b + 1, c=a / 2, d > 0)
//代码3
a = get_val();
count_val(a);
while (a > 0)
{
         //业务处理
        a = get_val();
        count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
         //业务处理
}

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

        1. [ ] 下标引用操作符 操作数:一个数组名 + 一个索引值

 int arr[10];//创建数组
 arr[9] = 10;//实用下标引用操作符。
 [ ]的两个操作数是arr和9。

        2. ( ) 函数调用操作符

        接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

 #include <stdio.h>
 void test1()
 {
 printf("hehe\n");
 }
 void test2(const char *str)
 {
 printf("%s\n", str);
 }
 int main()
 {
 test1();            //实用()作为函数调用操作符。
 test2("hello bit.");//实用()作为函数调用操作符。
 return 0;
 }

        3. 访问一个结构的成员

        . 结构体.成员名

        -> 结构体指针->成员名

10、常见操作符

auto,break,case,char,const,continue,default,do,double,else,enum,sxtern,float,for,goto,if,int,long,register,return,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile,while。

        这些关键字都是语言预先设计好的,用户自己是不能创造关键字的

自动循环

分支

数据类型修饰类型自定义类型
auto

break

continue

do    while

for

while

break

switch    case

dfault 默认

if else

go to

char

double

float

int   long

short

const

signed 有符号的

unsigned 无符号的

typedef 类型重定义

enum 枚举类型

struct 结构体类型

union 联合体类型

声明外部符号寄存器函数的返回计算变量类型大小函数返回、参数,修饰指针
externregisterreturnsizeofvoid

关键字typedef

typedef struct Node {
	int data;
	struct Node* next;
}Node;

关键字static

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

  1. 修饰局部变量,称为静态局部变量
  2. 修饰全局变量,称为静态全局变量
  3. 修饰函数,称为静态函数
//static.c
int g_val = 232;//全局变量,可外部链接
static int g_val = 232;//不可外部链接

//operator.c
//全局变量具有外部链接属性
//static修饰全局变量,改变了这个全局变量的链接属性,由外部链接属性变成了内部链接属性
//声明外部符号
extern int g_val;

int main() {
	//static修饰全局变量
	printf("%d\n", g_val);
	return 0;
}

11、#define定义常量和定义宏

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

//define定义宏
#define ADD(x,y) ((x)+(y))

int main() {
	int a = 10, b = 10;
	int c = ADD(a, b);
	printf("%d\n", c);
	return 0;
}

12、指针

  1. 指针是内存中一个最小单元的编号,也就是地址
  2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量

总结:指针就是地址,口语中说的指针通常指的是指针变量。

指针变量

        我们可以通过&(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个 变量就是指针变量。

int main(){
    int a = 10;//在内存中开辟一块空间 
    int* p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
    //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个指针变量。
    *p = 30;//解引操作符,*p就是a

    printf("%d\n", a);//打印a后a=30
    return 0;
}

        指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。

总结:

  • 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节。
char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;
//指针的定义方式是: type + *

1)指针+-整数

#include <stdio.h>
//演示实例
int main()
{
 int n = 10;
 char *pc = (char*)&n;
 int *pi = &n;
 
 printf("%p\n", &n);
 printf("%p\n", pc);
 printf("%p\n", pc+1);
 printf("%p\n", pi);
 printf("%p\n", pi+1);
 return  0;
}
//指针的类型决定了指针向前或者向后走一步有多大(距离)。

2)指针的解引用

#include <stdio.h>
int main()
{
 int n = 0x11223344;
 char *pc = (char *)&n;
 int *pi = &n;
 *pc = 0;   //重点在调试的过程中观察内存的变化。
 *pi = 0;   //重点在调试的过程中观察内存的变化。
 return 0;
}
//指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
//比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

3)野指针

        野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

1.指针未初始化

#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

2.指针越界访问

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

3.指针指向的空间释放

13、结构体

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

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

结构的成员可以是标量、数组、指针,甚至是其他结构体。

1)结构体定义和初始化

struct Point
{
	int x;
	int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = { x, y };
struct Stu        //类型声明
{
	char name[15];//名字
	int age;      //年龄
};
struct Stu s = { "zhangsan", 20 };//初始化
struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化

2)结构体成员的访问

1.结构体变量访问成员

        结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。

struct S s;
strcpy(s.name, "zhangsan");//使用.访问name成员
s.age = 20;//使用.访问age成员

2.结构体指针访问指向变量的成员

struct Stu
{
	char name[20];
	int age;
};
void print(struct Stu* ps)
{
	printf("name = %s   age = %d\n", (*ps).name, (*ps).age);
	//使用结构体指针访问指向对象的成员
	printf("name = %s   age = %d\n", ps->name, ps->age);
}
int main()
{
	struct Stu s = { "zhangsan", 20 };
	print(&s);//结构体地址传参
	return 0;
}

3.结构体传参

struct S
{
 int data[1000];
 int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
 printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
 printf("%d\n", ps->num);
}
int main()
{
 print1(s);  //传结构体
 print2(&s); //传地址
 return 0;
}


//首选print2函数。
//原因:
//函数传参的时候,参数是需要压栈的。
//如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的
//下降。

  • 27
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值