> 文章列表 > 初步了解C语言(下)

初步了解C语言(下)

初步了解C语言(下)

所属专栏:C语言
博主首页:初阳785
代码托管:chuyang785
感谢大家的支持,您的点赞和关注是对我最大的支持!!!
博主也会更加的努力,创作出更优质的博文!!
关注我,关注我,关注我,重要的事情说三遍!!!!!!!!

目录

1.关键字

1.1关键字typedef

1.2关键字static

1.2.1修饰局部变量

1.2.2修饰全局变量

1.2.3修饰函数

2.#define定义常量和宏

3.指针

3.1内存

3.2指针变量的大小

4.结构体


1.关键字

常见的关键字:

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

C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。 注:关键字,先介绍下面几个,后期遇到讲解。

这里auto的意思是自动的意思,我们在创建一个局部变量的时候:
 

#include<stdio.h>
int main()
{int a=0;//局部变量是进入作用域创建,出了作用域销毁,自动创建,自动销毁的。return 0;
}

局部变量是进入作用域创建,出了作用域销毁,自动创建,自动销毁的。

其实我们的局部变量前面都有个auto:
auto int a=0;

既然都有auto那不妨就把他省略了。

我们把他们分个类:

循环:break,coutinue,do while,for,while

分支:break,switch case,default(默认),if else,goto

数据类型:char,int,double,float,short,void

修饰类型:const,signed(有符号),unsigned(无符号),typedef(类型重定义)

自定义类型:enum(枚举类型),struct(结构体类型),union(联合体类型)

函数返回值:return

auot:自动

extern:声明外部符号

register:用于寄存器的

static:修饰静态变量

sizeof:计算变量/类型大小的单位字节

void:意为无/空,用于函数的返回值,函数的参数,修饰指针

volatile:这个关键字很少见,后面会详细介绍

下面我们具体将一些常见的。

1.1关键字typedef

typedef 顾名思义是类型定义,这里应该理解为类型重命名。

比如:

//将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名
typedef unsigned int size_t;
int main()
{//观察num1和num2,这两个变量的类型是一样的unsigned int num1 = 0;size_t num2 = 0;return 0;
}

这里就是将unsigned int 重命名为size_t,所以上面的num1和num2其实是一样的。

1.2关键字static

在C语言中:

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

1. 修饰局部变量-称为静态局部变量

2. 修饰全局变量-称为静态全局变量

3. 修饰函数-称为静态函数

1.2.1修饰局部变量

我们看一串代码:
 

//代码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;
}

上面的值会是什么呢?

代码展示:
11b12cd6655f49b6b48612d4616279c9.png

我们看到了输出的是10个1,这是因为我们的test函数里面的i是局部变量,局部变量的特点是进作用域创建,出作用域销毁,这里我们每次进入test函数都会创建一次 i,每出一次都会销毁i,因为这个我们每次创建的i初始值都是0在进行 i++得到1,所以我们每次打印的都是1。 

拿如果我们在test函数里面的 i 前面加上static会曾么样呢?

f399fc373d36412fbdb58afeccb2e277.png

 这里我们得到了不同的结果,我们test函数里面的 的值得到了累加效果,这也就是说明我们的test函数里面的 i 出作用域并没有销毁,所以我们每次进入函数的时候都不会再次创建i变量(只会在第一次进入的时候创建)。

对比代码1和代码2的效果理解static修饰局部变量的意义。

结论: static修饰局部变量改变了变量的生命周期 让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。

我们的C/C++代码学习的时候,我们把内存大概划分为3个区域:

静态区:

局部变量;

形式参数;

临时的作用的变量都是在栈区。

栈区的特点:进入作用域创建,出作用域销毁。

栈区:

动态内存分配:
malloc,calloc,realloc,free

堆区:

全局变量;

静态变量;

静态区的特点:创建好后,直到程序结束后才销毁(还给操作系统)

所以上面被static修饰局部变量改变了变量的存储类型(位置,从栈区到了静态区)使得静态变量的生命周期变长,直到程序结束才销毁。但是作用域不变。

1.2.2修饰全局变量

当我们在一个空项目里面写代码的时候,我们难免会创建多个源文件来链接代码,这个时候我们如果想要在一个源文件里面使用另一个源文件的变量的时候我们就要使用到一个关键字extern外部声明符号:

b592bcf7e85e4b7aa4c3e163fa0a4d72.png

    为什么可以使用外部的全局变量呢?

原因是局部变量具有外部连接属性。     

但是如果我们在他前面加上static是就无法是用了:

57f9139db29042c2b6126ca4c28aa91e.png

 这里报错说无法解析的外部符号,就是再说找不到arr。

这是因为当全局变量被static修饰的时候,改变了这个全局变量的连接属性,由外部连接属性变成内部连接属性。这个静态变量只能在所在的源文件使用,不能个在其他的源文件使用了。

1.2.3修饰函数

static修饰函数和static修饰全局变量是一样的:

0235b940a89c4665a8ca02e7d17dba30.png

3681f45546a342e0882819a7a9ccf313.png

这里同样显示了无法解析的外部符号。 

2.#define定义常量和宏

2116ece542414c1d9ed66a0b6bf24ebf.png

 上面就是#define定义产量,我们打印a和MAX得到的结果是一样的,其实#define定义常量就是一个替换的结果,这里就是说用MAX替换1000,所以打印的结果是一样的。

eb9d2fd9e3144544a5fd562f76bdbca6.png

 #define定义宏也是一样的,也是一个替换的结果。

这里int sum=ADD(2,3)==((2)+(3)) 就是这样的一个替换。

3.指针

    在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接
    指向(points     to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需变 
    量单元,可以说,地址指向该变量单元。因此将地址形象化的称为"指针"。意思是通
    它能找到以它为地址的内存单元。
 
简单点说:
    内存是一块大大的空间,为了很好的使用内存,把内存划分成一个个小格子,在给每 个格子编个号,就像生活当中旅馆当中每个房间都用个编号一样,这个时候,再加上旅馆的街道房间编号,此时就组成了地址。
    你也可以对比地图,在地图上找到一个地方,要找的这个地方首先的知道这个地方的地址。

fa305607f6cb48a790ad2678c6184e45.png#pic_center
 此图:是以16进制的形式来展示的,如果是二进制形式来展示的话,地址展示会很长,不易展示,也不宜理解 一个内存单元的大小是一个字节。

3.1内存

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

我们来写一个简单的指针:
 

#include <stdio.h>
int main()
{int a=10;int* pa=&a;return 0;
}

上面我们就创建了一个指针变量pa,我们来分析一下int* pa=&a;

我们的指针有个特点就是有一个(*)这个就代表我们创建的变量是一个指针变量,所以pa就是一个指针变量,而(*)前面是变量的类型,这里就是a的类型,而我们=后面的是我们想要给它赋的地址,这里赋值了a的地址(&是取地址符号,就是取出a的地址的意思)

我们要使用也是很好理解的:
 

#include <stdio.h>
int main()
{int a=10;int* pa=&a;printf("%d",a);printf("%d",*pa);*pa=20;printf("%d",a);return 0;
}

这里我们打印的时候(*)的作用又不一样了,这个时候的(*)叫做解引用操作,意思就是通过我们赋值的地址找到地址里面的值,所以这里的*pa==a,所以他们打印的结果是一样的。

同时我们的pa既然是指针变量,那终究是个变量,所以是可以被修改的,这里我们就通过解引用操作找到a的值并进行修改即:*pa=20,所以后面对a打印的结果是20.

3.2指针变量的大小

我们知道类型是有大小的。

我们的int是4个字节

char是一个字节

double是8个字节

……

我们的指针其实也是一个类型,叫做指针类型,所以他也是有大小的。

我们看以下代码的结果。

8f43b50482cc4d5f8a201ed9d1e93d24.png#pic_center
不难看出无论是什么类型的指针,他的大小都是一样的,都是8个字节(当前我的电脑是64位平台的,如果是32位平台的,那他们的值都是4个字节)。

也就是所我们的指针类型是固定大小的,而且大小取决于我们电脑硬件的。

4.结构体

我们上一节说过了数组数据类型相同的数的集合,但是在我们的日常实际生活中大多数是将不同类型数据集合在一起。

就比如说我们要描述一名学生的信息,我们要知道他的名字,他的年龄,他的身高,他的体重等等,这里涉及到了整形,字符类型,浮点型等,拿我们怎么将他们集合在一起呢?

这个时候C语言引入了结构他来集合这些复杂类型。

我们的结构体关键字:struct

他的语法形式:

struct Stu
{//成员结构
};

比如:

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

我们的成员初始化和数组是很像的,也是用一个花括号括起来:
 

struct Stu s = { "张三",20,"男","123456" };

如果我们要打印出来怎么办呢?

这个时候我们引入了(.)点操作符,结构体变量+ . +成员名:

352c1a021be04913b7c35a9dabe09baa.png

我们结构体访问成员还有一个操作符(->)箭头操作符。

它的适用语法:结构体指针->结构体成员

我们来简单的实现一下:
 

#include <stdio.h>void printf1(struct Stu* ps)
{printf("name = %s age = %d sex = %s id = %s\\n", ps->name, ps->age, ps->sex, ps-
>id);}
struct Stu
{char name[20];//名字int age;      //年龄char sex[5];  //性别char id[15]; //学号
};
int main()
{struct Stu s = {"张三", 20, "男", "20180101"};struct Stu* x=&s;printf1(x);printf("name = %s age = %d sex = %s id = %s\\n", s.name, s.age, s.sex, s.id);return 0;
}

你会发现上面两个printf打印的结果是一样的。

总结一下就是我们的结构体访问的方式有两种:

1. 结构体变量.成员(.操作符)

2. 结构体指针.成员(->箭头操作符)

好了到这里我们的C语言的大概内容就讲完了,但是我先说的是这些都只是初步的了解,如果有些小伙伴们有些没看懂不要慌张,后面我们会详细的讲解每一个知识点,带领大家一步一步的了解C语言,了解编程语言。

好了都到这里点个关注和鼓励的小点赞吧!!!!!!!!!!!!