C语言---初始C语言

news2024/11/23 21:12:00

1、初始C语言

1、编译器主要有:Clang、GCC、WIN-TC、MSVC、Turbo C等

什么是编译?

test.c----------------------------->test.exe

这个过程需要经过编译链接等过程,而众多编译器实现的功能就是把我们写的test.c进行编译。

2、VS2022(IDE)安装

官网:https://visualstudio.microsoft.com/zh-hans/?rr=https://www.microsoft.com/zh-cn/

在这里插入图片描述

在这里插入图片描述

文件说明:

  • .c结尾的文件称为源文件
  • .h结尾的文件称为头文件

下面创建一个源文件

在这里插入图片描述

在这里插入图片描述

3、第一个C语言项目:

#include <stdio.h>
int main()
{
	printf("hehe\n");         
	return 0;
}

//VS中点击F5运行
//C语言中一定要有main函数,main函数是程序的入口
//标准的主函数的写法
int main()
{
    return 0;
}
//这里有个对应的关系,return “0”和int相对应,int是整数类型,0是整数
//printf是个库函数,是别人开发好我们可以直接使用的,所以说在使用之前我们需要声明一下,所以“#include <stdio.h>”就是个说明
//std---代表标准的意思,i---代表input,o---代表output,所以说stdio.h就是标准的输入输出的头文件

4、数据类型

char                    //字符数据类型
short                   //短整型
int                     //整形
long                    //长整型
long long               //更长的整形
float                   //单精度浮点数
double                  //双精度浮点数
int main()
{
	printf("%d\n", 100);       "%d"以整形的方式打印,可以把"%d"---改为"%zu"
	return 0;
  • 每一个数据类型有多大呢?这里使用一个库函数来显示出来
int main()
{
	printf("%d\n", sizeof(char));
	printf("%d\n", sizeof(short));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof(long));
	printf("%d\n", sizeof(long long));
	printf("%d\n", sizeof(float));
	printf("%d\n", sizeof(double));
	return 0;
}

1
2
4
4
8
4
8
//以上单位为“字节”
//可以发现int数据类型大小怎么和long的数据类型大小一样呢?
//原因:C语言规定:sizeof(long)>=sizeof(int)

4.1、%+字母

%d-----------打印整型(有符合整型)
    
%u-----------用于打印unsigned int num = 0这样的数据类型,这是无符号整型
    
//有符号整形包含正负数,无符号整型不包含复数。

%c-----------打印字符
    
%s-----------打印字符串
    
%f-----------打印float类型的数据
    
%lf----------打印double类型的数据
    
%zu/zd----------打印sizeof()的返回值
 
%p-----------打印地址
    
%02d--------------输出02/05...这样的效果
    
%2d---------------输出 2/ 5   //也就是说前面的0被空格替代了。
    
%-2d-------------左对齐
    
%.1f--------------打印小数点后一位的小数
    
float a = 0.0f       //float类型数据进行初始化
    
double a = 0.0       //double类型数据进行初始化
    //一般的直接赋值3.14编译器认为它是double类型的数据,为不是float类型的。
a=2 c=1 b=5 8
a=2 c=1 b=7 10
            12
            14
            16

4.2、计算机单位

bit---------比特位,计算机二进制101010101010。存储一个“1”或者“0”就占用一个bit位

byte-------字节 ,1字节=8bit

kb----------1kb=1024个byte

Gb----------

tb------------

pb------------

4.3、简述变量的本质

int main()
{
	int age = 22;         //age = 22赋值的这个过程叫做初始化,如果不进行赋值初始化,那么这个变量是随机值,这样一来这个变量不好掌控,所以尽量进行初始化。
	return 0;
}

//int整数类型大小为4字节,实际上就是向内存申请了一个4字节的内存大小,命名为age,用来存储“22”这个数据的。

5、变量和常量:局部变量和全局变量

不变的量/不可修改的量,C语言中用常量来表示,变得值C语言中用变量来表示

5.1、定义变量的方法

int main()
{
	int age = 22;
	return 0;
}

5.2、变量的分类

  • 局部变量
  • 全局变量
#include <stdio.h>

int global = 2019;    //全局变量
int main()
{
	int local = 2018;
	int global = 2020;     //局部变量
	printf("global = %d\n", global);          //那这里global值为什么?
	return 0;
}

输出:
    2020

所以可以得出结论:当全局变量和局部变量名字相同的情况下,局部变量优先。当然如果只有全局变量那么就会显示全局变量

错误代码示例:同一个范围里面不能声明重复的变量:

int main()
{
	int local = 2018;
	int local = 2020;    
	return 0;
}
//会报错

5.3、变量的使用—写一个代码,计算2个整数的和

#include <stdio.h>
//scanf是一个输入函数
int main()
{
	int num1 = 1;
	int num2 = 2;              //初始化
	
	//输入两个整数
	scanf("%d %d",&num1,&num2);

	//求和
	int sum = num1 + num2;

	//输出
	printf("%d\n", sum);
	return 0;

}

此时运行会发现报如下错误:

在这里插入图片描述

解决办法:在源文件的第一行写入如下代码:

#define _CRT_SECURE_NO_WARNINGS

//但是我们也能看到提示说可以用scanf_s这个函数代替,值得说明一下:scanf_s是VS编译器自己提供的函数,而非标准C提供的函数。

5.4、变量的作用域和生命周期

__作用域:__作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不是总是有效的/可用的

简单来说就是:这个变量在哪里起到作用/使用,哪里就是它的作用域

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

5.4.1、局部变量的作用域是变量所在的局部范围

代码演示:

#include <stdio.h>
int main()
{
	{
		int a = 10;
		printf("a=%d\n", a);           //这个可以输出
	}
	printf("a=%d\n", a);               //但这个就会报错
	return 0;
}

但如果是这样的呢?

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


输出:
    a=10
    a=10
//此时a变量的作用域是整个的第一个大括号,所以都会输出

5.4.2、全局变量的作用域是整个工程

代码演示:

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

输出:
    a=10
    a=10

5.4.2.1:补充:声明来自外部的符号

extern int a;      //声明变量
extern int Add(int x,int y);         //声明函数

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

1、局部变量的生命周期是:进入作用域之后生命周期开始,出作用域生命周期结束/销毁。

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

比如:

#include <stdio.h>

void test()
{
	int n = 1;
	n++;
	printf("%d ", n);
}

int main()
{
	int i = 0;
	while (i < 10)
	{
		test();
		i++;
	}
	return 0;
}

输出:
    2 2 2 2 2 2 2 2 2 2

这个重点就是看test()中a变量的声明周期,a变量从调用test函数到{开始就创建了,然后到}就销毁了,所以说输出一直是22222222…,而不是2,3,4,5,6…

6、常量

常量就是不变的量/不可修改的量

C语言中的常量和变量的定义形式有所差异。

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

  • 字面常量
  • const修饰的常__变__量
  • #define定义的标识符常量
  • 枚举常量

6.1、字面常量

#include <stdio.h>
//1.字面常量
int main()
{ 
	14;          //整形常量
	3.14;       //浮点型常量
	'w';        //字符常量,单个字符用单引号''
	"asdf";     //字符串常量,字符串用双引号""
	return 0;
}

6.2、const修饰的常__变__量

为啥叫做常变量呢?首先我们先来看一下常规的变量:

int main()
{ 
	int a = 10;
	a = 20;                 //进行变量赋值,变量改变,最终输出20
	printf("%d\n", a);
	return 0;
}

上面的a变量是可以被修改的,那如果我们不行要修改呢?我们只需要声明const即可

int main()
{ 
	const int a = 10;            //
	printf("%d\n", a);
	return 0;
}

补充:在C语言中,const修饰的a,本质是变量,但是不能被修改,有常量的属性。

6.3、define定义的标识符常量

#define	MAX 100                       //MAX就是个标识,这里定义的值也可以为字符串,浮点型...
#include <stdio.h>
int main()
{
	printf("%d\n", MAX);
	return 0;
}

 输出:
    100

define定义的常量既可以用来直接打印也可以用来赋值。

#define	MAX 100
#include <stdio.h>
int main()
{
	printf("%d\n", MAX);
	int a = MAX;
	printf("%d\n", a);
	return 0;
}

输出:
    100
    100

6.4、枚举常量

#include <stdint.h>

enum Color
{
	//下面的三个变量就是枚举常量
	RED,
	GREEN,
	BLUE
};

int main()
{
	enum Color c = RED;
	return 0;
}

7、字符串

1、首先char是字符类型,并不是字符串类型,那么C语言中有没有字符串类型呢?答案是没有!

那我们怎么表示字符串呢?使用双引号""来表示

"hello bit.\n"

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

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

2、那我们怎么存储字符串呢?我们如何认识到__\0__的重要性呢?

#include <stdio.h>
int main()
{
	char arr1[] = "abcdef";         //存储字符串的形式
	char arr2[] = { 'a','b','c','d','e','f' };
	printf("%s\n", arr1);
	printf("%s\n", arr2);            //%s是以字符串的形式显示
	return 0;
}

输出结果:

在这里插入图片描述

为什么会出现如此现象呢?

  • 首先分析第一个,arr1数组,字符串后面隐藏了\0,所以程序在执行时,遇见了\0便结束了,所以说输出就是abcdef
  • 那么第二个arr2数组,没有\0所以程序在’f’之后并不会结束,直到什么时候遇见\0什么时候程序才会停止。因此输出以上内容。

那如果arr2数组我们向正常输出呢?我们可以手动添加一个\0

char arr2[] = { 'a','b','c','d','e','f',"\0"};

!!!可见字符串中\0的重要性

那如果是这样的呢?

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[3] = { 'b','i','t' };
	printf("%d\n", strlen(arr));
	return 0;

输出:

在这里插入图片描述

为什么呢?明明我声明了arr[3],arr数组有三个元素,但为什么该字符串的长度还是随机值呢?因为我们赋值初始化就三个元素,而我恰恰声明了三个空间,所以‘t’后面并没有\0,所以会一直检索到后面的\0才会输出。

那换一种写法:

char arr[4] = { 'b','i','t' };     //上述代码就改变这一行,arr[3]--->arr[4]

输出:3

原因:我们声明了分配4个存储空间,而后面要存储的元素只有3个,所以第四个空间直接是0值,相当于\0的作用,所以到此停止,该字符串的长度为3。

3、下面我们在举个例子说明下\0的重要性

这里我们使用一个库函数:strlen—用于输出字符串的长度,这个需要头文件:#include <string.h>

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = { 'a','b','c','d','e','f'};
	printf("%d\n", strlen(arr1));
	printf("%d\n", strlen(arr2));
	return 0;
}

输出结果:
在这里插入图片描述

同样的道理arr1遇见f后面的\0之后就停止了,并且\0不算字符串内容,所以输出字符串长度为6

而arr2遇见f后面并没有\0,所以不会停止,继续向后遍历,直到遇到\0,以你输出不是6而是33

那如果想要arr2正常输出字符串长度我们只需要手动添加\0即可

char arr2[] = { 'a','b','c','d','e','f','\0'};

8、转义字符

常见转移字符,下面所有的转义字符,都是一个字符,注意:是一个字符

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

后面两个转义符代码演示:

#include <stdio.h>
int main()
{
	printf("%c\n", '\130');   //特别强调,'\130'不是4个字符,而是一个字符
	printf("%c\n", '\x62');   //同理,'\x62'不是4个字符,而是一个字符
	return 0;
}

输出:

在这里插入图片描述

8.1、关于转义字符的一道题

统计下面字符串的长度

#include <stdio.h>
#include <string.h>
int main()
{
	printf("%d\n", strlen("c:\test\628\test.c"));
	return 0;
}

答案:14

分析:\t算一个字符,\62算一个字符,所以一共由14个字符

那为啥\62算一个字符呢?我们说\ddd是需要三个数字的呀?为什么后面的“8”不算呢?

因为\ddd表示的是八进制数字,八进制数字是从0~7的,是不包含8的,所以只有\62算一个转义符。

9、注释

10、选择语句和循环语句

1、选择语句

if (aa == 1)
{
	printf("ok,去玩");
}
else
{
	printf("废了");
}

2、循环语句

C语言中如何实现循环呢?

  • while语句
  • for语句
  • do…while语句
while ()
{
    
}

11、函数

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}

int main()
{
	int n1 = 0;
	int n2 = 0;
	//输入
	scanf("%d %d", &n1, &n2);
	//求和
	int sum = Add(n1,n2);
	//输出
	printf("%d\n",sum);
	return 0;
}

在这里插入图片描述

12、数组

问题:要存储0~9的数字,怎么存储?

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

#include <stdio.h>
int main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
    printf("%d\n", arr[3]);       //遍历数组
	return 0;
}

arr[10],这个10,就是表示我要存储10个int类型的元素,当然不写10也行,程序会自行分配

并且这些元素在内存中都是有顺序的,从0开始…

这些序号,叫做数组的下标,下标是从0开始的。

遍历全部元素:

#include <stdio.h>
int main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int i = 0;
	while (i < 10)
	{
		printf("%d\n", arr[i]);
		i++;
	}
	return 0;
}

那如果是这样的呢?

int arr[10] = { 0 };

那这10个空间存储的全部是0

在这里插入图片描述

13、操作符

13.1、算数操作符

+    -    *    /(得整数部分)    %(取模,得余数)

//  7 / 2    ----->3
//  7 % 2    ----->1
    
//那如果想要打印出小数呢?只需要两端有一个浮点数就会执行浮点数得出发
#include <stdio.h>
int main()
{
	float a = 7 / 2.0;
	printf("%.1f\n",a);          //.1就是保留小数点后一位
	return 0;
}

13.2、移位操作符

>>   <<

13.3、位操作符

&   ^   |

13.4、赋值操作符

=   +=   -=   *=   /=   &=   ^=   |=   >>=   <<=
  • a = a+3 a += 3是一样的效果,那后面的那都是这个原理

13.5、单目操作符

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

在C语言中0代表假,非0代表为真

13.5.1、!的介绍

#include <stdio.h>
int main()
{
	int flag = 0;           //flag初始化为0,所以flag此时为假
	if (!flag)              //那既然flag为假,那么!flag就为真
		printf("现在为真");
	return 0;
}

13.5.2、sizeof的使用介绍

#include <stdio.h>
int main()
{
	int a = 10;
	printf("%d\n", sizeof(a));        //4
	printf("%d\n", sizeof(int));      //4
	printf("%d\n", sizeof a);         //因为size是个操作符,所以不带()也可以使用   输出:4

	return 0;
}

当然sizeof也可以统计数组的类型大小

#include <stdio.h>
int main()
{
	int arr[10] = {0};
	printf("%d\n", sizeof(arr));            //40
	printf("%d\n", sizeof(arr[0]));        //4,
	printf("%d\n", sizeof(arr) / sizeof(arr[0]));       //计算数组中元素的个数的方法
	return 0;
}

13.5.3、–、++的使用

这里只说明一个++即可,–的使用同理

1、先说后置++,eg:a++,后置++遵循一个原则:先使用,后++

#include <stdio.h>
int main()
{
	int a = 10;
	int b = a++;           //先使用,后++,也就是先 int b = a,然后在a = a+1
	printf("%d\n", b);
	printf("%d\n", a);
	return 0;
}

输出:
    10
    11

2、前置++,eg:++a。前置++遵循一个原则:先++,后使用

#include <stdio.h>
int main()
{
	int a = 10;
	int b = ++a;           //先++,后使用,也就是先 a = a+1,然后在int b = a
	printf("%d\n", b);
	printf("%d\n", a);
	return 0;
}

输出:
    11
    11

13.5.4、强制类型转换

#include <stdio.h>
int main()
{
	int a = (int)3.14;
	printf("%d\n", a);
	return 0;
}

输出:
    3

13.6、关系操作符

>
>=
<
<=
!=          //用于测试不相等
==          //用于测试相等

13.7、逻辑操作符

&&       逻辑与/并且
||       逻辑或/或者

13.8、条件操作符

exp1?exp2:exp3
    
exp1 ? exp2 : exp3
 真     算     不算      那么整个表达式的结果就是exp2表达式的结果
 假    不算     算       那么整个表达式的结果就是exp3表达式的结果

代码示例:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int r = a > b ? a : b;      //比较最大值
	printf("%d\n", r);
	return 0;
}

输出:
    20

在这里插入图片描述

分析:如果a>b(exp1)成立,则a(exp2)是对的,那么b(exp3)是错的,因此整个表达式的结果就是exp2的结果,因为a=10,所以整个表达式的结果就是10,所以存进r=10

但是这里显然b(exp3)是对的,又因为b=20,所以r=20来进行存储,所以输出最大值为20。

13.9、逗号表达式

exp1,exp2,exp3,...expN

逗号表达式就是用逗号隔开的一串表达式。

逗号表达式的特点是:从左向右依次计算,整个表达式的结果是最后一个表达式的结果。

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c = 0;
	int d =(c = a - 2, a = b + c, c - 3);    //最后一个表达式c-3=5,所以最终输出结果5
	printf("%d\n", d);
	return 0;
}

输出:
    5

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

[]   ()   .   ->

13.10.1、下标引用

printf("%d\n", arr[0]);

13.10.2、函数调用

Add()
    

14、常见关键字简介

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

关键字是C语言内置的

15、关键词typedef和static

15.2、关键字typedef

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

typedef只能对类型进行重命名

比如:

#include <stdio.h>
//将unsigned int 重命名为unit,所以unit也是一个类型名
typedef unsigned int unit;
int main()
{
	//观察num1和num2,这两个变量的类型是一样的
	unsigned int num1 = 0;
	unit num2 = 0;
	return 0;
}

15.3、关键字static

在C语言中:

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

  • 修饰局部变量—称为静态局部变量
  • 修饰全局变量—称为静态全局变量
  • 修饰函数—称为静态函数

15.3.1、static修饰局部变量

我们先看看段代码:

#include <stdio.h>

test()
{
	int n = 1;
	n++;
	printf("%d ", n);
}

int main()
{
	int i = 0;
	while (i < 10)
	{
		test();
		i++;
	}
	return 0;
}

输出:

在这里插入图片描述

__分析:__还记得上面所说得变量得生命周期,变量得生命周从进入作用域开始创建,到出作用域销毁。

在第一遍调用test函数时,n这个变量从{开始创建,到}开始销毁,然后中间n++,所以最终打印出来n=2,这个时候test函数调用完毕,此时已经没有n变量这个东西了,因为已经销毁了,然后第二遍调用test函数,然后从头开始创建n变量并赋值n=1,然后打印n=2,然后销毁n变量,所以最终打印效果:2 2 2 2 2 2 2 2 2 2

那么ok下面进入整体,我们使用static关键词,来修饰局部变量,看看有什么效果:

#include <stdio.h>

test()
{
	static int n = 1;                //这里使用static关键词修饰局部变量n变量
	n++;
	printf("%d ", n);
}

int main()
{
	int i = 0;
	while (i < 10)
	{
		test();
		i++;
	}
	return 0;
}

输出:

在这里插入图片描述

???为什么打印得效果不一样了呢?

原因分析:同样第一遍调用test函数,创建n变量并赋值n=1,然后n++,然后打印n=2,重点来了:由于n变量用static关键词修饰了,那么此时n变量即使出了此作用域后,n变量依然不会被销毁,这就是static关键词的作用此时n=2被储存起来了,然后第二遍调用test函数,此时“static int n = 1;”这一句话就相当于不起作用也能够了,由于时n=2,然后n++,所以n=3了,最后出test函数后,n变量依然不会被销毁,n=3就被存起来了,就这样循环下去,所以输出结果就如上。

总结:static修饰局部变量的时候,局部变量出了作用域,局部变量不会被销毁。

本质上,static修饰局部变量的时候,改变了变量的存储位置。

在细致解剖一下就是:

一块大内存,是分区域存储的,分为:栈区、堆区、静态区

在这里插入图片描述

变量被static修饰后,此变量就从栈区移动到了静态区,但代码这里n直接就是在静态区了,不存在转换,这里只是特殊说明一下,所以说static修饰局部变量的时候,改变了变量的存储位置。

15.3.2、static修饰全局变量

先来看段代码:

在这里插入图片描述

分析:我们把g_val变量放在一个源文件中,然后在另一个源文件中调用打印g_val变量,(两个源文件在同一个项目中)此时只需要使用关键字extern声明一下就行了

然后我们使用static关键字修饰一下g_val,这时在另一个源文件中就算使用关键字extern声明g_val变量,但g_val依然不能被使用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gUmQ2Abk-1685426179194)(C:\Users\郑波\AppData\Roaming\Typora\typora-user-images\1684597115195.png)]

总结:全局变量时具有外部链接属性的,而一旦static修饰全局变量的时候,这个全局变量的外部链接属性就变成了内部链接属性,其它源文件就不能在使用这个全局变量了,那这个全局变量的作用域由整个工程变为了当前文件,且此时静态全局变量是存储在静态区里面的。

15.3.3、static修饰函数

先来看一段代码:实现两个数相加

#include <stdio.h>

int Add(int x,int y)
{
	return x + y;
}

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

输出:
    30

上面代码使用了一个Add函数用于实现两个数相加,我们可以把Add函数放在test01.c文件中去,然后main函数放在test02.c文件中去,然后调用Add函数。同样我们也使用extern关键词来声明一下Add函数(其实不声明也行但是有警告)

在这里插入图片描述

然后我们使用static关键字修饰一下Add函数,这时在另一个源文件中就算使用关键字extern声明Add函数变量,但Add函数依然不能被调用了:

在这里插入图片描述

总结:一个函数本来是具有外部链接属性的,而一旦static修饰的时候,这个函数的外部链接属性就变成了内部链接属性,其它源文件就不能在使用这个函数了。

15.4、【普及】关键字register—寄存器

在这里插入图片描述

由于CPU处理数据速度非常之快,以至于内存赶不上CPU的速度,所以当处理数据时,内存中的数据向上一级存放,于是就放到在高速缓存、寄存器里面。

那进入整体,在写代码时我们也可以写出寄存器变量:

#include <stdio.h>
int main()
{
	//寄存器变量
	register int num = 3;     //建议把‘3’存放在寄存器里面
	return 0;
}

当把‘3’数据存放在寄存器里面了,这样在读取此数据时会更快,但是需要注意一点,这里只是建议存放,那到底最后是否存放在寄存器里面时编译器说的算。

16、define定义常量和宏

16.1、#define定义常量

这个知识点就是前面讲到常量所涉及到的

#define	MAX 100                       //MAX就是个标识,这里定义的值也可以为字符串,浮点型...
#include <stdio.h>
int main()
{
	printf("%d\n", MAX);
	return 0;
}

 输出:
    100

16.2、#define定义宏

宏是有参数的

上面我们用了Add函数来实现两数之和,这里我们使用宏来代替Add函数实现此功能

#include <stdio.h>

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

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

在这里插入图片描述

17、指针

17.1、内存

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

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

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

在这里插入图片描述

好的,那现在有个问题:如果有个整形变量数据为“10”,(int a = 10)那int数据类型需要占用4个字节,那就需要向内存申请4个存储单元,那么变量a的内存地址是哪个呢?如下图:

在这里插入图片描述

比如分配的内存地址如下图所示:分配的4个内存空间为:5,6,7,8
在这里插入图片描述

那么此时变量a的内存地址就是第五个地址(首地址)

17.2、如何打印变量内存地址,如何存储内存地址?

1、打印内存地址

&a //取地址操作符

#include <stdio.h>
int main()
{
	int a = 10;
	printf("%p\n", &a);           //打印内存地址
	return 0;
}

2、存储内存地址:

#include <stdio.h>
int main()
{
	int a = 10;
	int* p = &a;            //存储变量a的内存地址
	return 0;
}

17.3、指针变量

重点来了:

int* p = &a;       这个变量p就是指针变量

为什么变量p就被称作为是指针变量呢?

其实很简单,我们都知道每一个内存单元都会有一个编号,又叫做地址,而地址又被称作指针。

在这里插入图片描述

如果变量a的数据类型字符类型,就需要这样写:

#include <stdio.h>
int main()
{
	char a = 10;
	char* p = &a;            //存储变量a的内存地址
	return 0;
}

17.4、*p代表的意思和作用

看一段代码

#include <stdio.h>
int main()
{
	int a = 10;
	int* p = &a;            
	*p = 20;          //解引用操作符,意思就是通过p中存放的地址,找到p所指向的对象,*p就是p指向的对象
	printf("%d\n", a);
	return 0;
}

输出:
    20

*p = 20就感觉重新给a = 20赋值一样。(个人分析:*p和直接赋值还是又差别的,*p是找到内存地址进行赋值,这个操作a变量的地址是没有改变的,而重新赋值a变量的内存地址应该是改变了。)

17.5、指针变量的大小

#include <stdio.h>
int main()
{
	printf("%zu\n", sizeof(char*));
	printf("%zu\n", sizeof(int*));
	printf("%zu\n", sizeof(short*));
	printf("%zu\n", sizeof(float*));
	printf("%zu\n", sizeof(double*));
	return 0;
}

//64bit位的电脑上
输出:
    8
    8
    8
    8
    8
    
    
//32bit位的电脑上
    4
    4
    4
    4
    4

原因分析:不管是什么类型的指针,都是在创建指针变量。指针变量是用来存放地址的。指针变量的大小取决于一个地址存放的时候需要多大空间,而32位平台下的地址是32个bit位—即4byte,所以指针变量的大小是4个字节,而64位平台下地址是64个bit位—即8byte,所以指针变量的大小是8个字节。

18、结构体

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型

比如描述学生,学生包含:名字+年龄+性别+学号这几项信息。因为学生是需要这几个信息同时包含的,属于复杂对象,所以用char,short,int,long…等数据类型不能够单一去表示。所以为了解决相应的问题,C语言就给自定义类型的能力就是结构体。

结构体就是把一些单一类型组合在一起。

那这里只能使用结构体来描述了:

struct Stu
{
    //以下都是结构体成员
	char name [20];
	int age;
	char sex[5];
	char id[15];
};

18.1、用结构体类型来创建一个变量,并打印信息

我们知道创建一个变量很简单,都是数据类型+变量名,比如:

int a 
char t
float dd

那同样上面的struct Stu结构体也是个类型,然后它也能创建变量:struct Stu S,这个S就是变量,

可以发现struct Stu{...}和int的效果一样,只不过int是解决单一变量问题的,而struct Stu解决复杂变量问题的,所以说struct Stu{...}int一样是不占空间的,只有当struct Stu S动作发生,创建出来的S变量才占用一点空间。

那如何使用变量呢?

#include <stdio.h>

struct Stu
{
	char name [20];
	int age;
	char sex[5];
	char id[15];
};

int main()
{
	struct Stu S = 
	{
		"zhangsan",17,"nan","123456789"
	};
    printf("%s %d %s %s\n",S.name,S.age,S.sex,S.id);  //打印的顺序需要相互对应
	return 0;
}

18.2、难度升级一下,问:能不能用指针区实现打印信息的效果?

代码如下:

#include <stdio.h>

struct Stu
{
	char name [20];
	int age;
	char sex[5];
	char id[15];
};

void print(struct Stu* ps)
{
	printf("%s %d %s %d\n", (*ps).name, (*ps).age, (*ps).sex, (*ps->id));
    printf("%s %d %s %d\n", ps->name, ps->age, ps->sex, ps->id);
    //效果一样,形式:结构体对象.结构体成员变量

}

int main()
{
	struct Stu S = 
	{
		"zhangsan",17,"nan","123456789"
	};
	print(&S);
	return 0;
}

就类比前面说到的指针变量那一节,道理一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/588569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何把“困在”内网的数据释放,进行安全的流转传输呢?

互联网大时代&#xff0c;数据的生产使用与互联网紧密相关&#xff0c;但数据安全和网络安全却既有联系又互不相同。数据安全和网络安全的突出区别是核心主体不同&#xff0c;数据安全关注的数据全生命周期的安全&#xff0c;而网络安全则是侧重保障网络体系和网络环境的安全性…

硬卷完了!低代码打怪升级进阶成神之路(2023年最新版)

一、背景 应用开发周期长一直是IT部门和业务部门面临的问题。 IT部门总是被新的应用需求弄得不堪重负。他们不可能完成业务部门想要完成的每一个项目。同时&#xff0c;业务部门的用户厌倦了等待&#xff0c;并开始完全绕过IT部门。 今天&#xff0c;我们来探索一下“低代码开发…

制药企业高效过滤器检漏参考法规、方法及操作步骤

对制药企业来讲&#xff0c;高效过滤器检漏主要是现场检漏&#xff0c;通过DOP法来发现滤器本身及运输、安装过程中可能存在的问题。常使用气溶胶光度计及多分散气溶胶进行检漏。依据的标准是2010药品GMP指南(测试方法采用ISO14644-3)。 对于制药企业来说&#xff0c;高效过滤器…

自动驾驶TPM技术杂谈 ———— 边缘检测

文章目录 介绍边缘检测与微分运算离散信号的差分滤波Robert算子Prewitt算子Sobel算子拉普拉斯算子 介绍 计算机视觉&#xff08;Computer Vision&#xff0c;CV&#xff09;是一门使用计算机模拟生物视觉的学科&#xff0c;目的是使用计算机代替人眼实现对目标的识别、分类、跟…

3.2. 数学类(Math、BigInteger、BigDecimal)

1. Math类 Math类提供了一些基本的数学函数&#xff0c;如求平方根、绝对值、三角函数等。它是一个final类&#xff0c;并且所有的方法都是static的&#xff0c;因此无需创建对象&#xff0c;直接使用类名调用方法即可。 以下是Math类的一些常用方法&#xff1a; abs(double…

抖音seo源码-抖音搜索源码-抖音下拉词-抖音关键词排名系统搭建

为了优化抖音平台上的内容&#xff0c;开发抖音关键词排名系统成为了必要的措施。该系统可以针对搜索结果和下拉词进行分析&#xff0c;为用户提供更准确的搜索结果。为实现这一目标&#xff0c;开发团队进行了大量的市场调查和用户研究。 在开发过程中&#xff0c;团队利用了…

mysql8+忘记密码的详细解决方法

mysql8忘记密码的详细解决方法 不同的版本&#xff0c;可能处理的方式不一样&#xff0c;这里说一下8以上的版本处理密码忘记的问题&#xff0c;windows系统。 一.问题&#xff1a; 太久没用mysql &#xff0c;忘记了原先的root密码 二&#xff1a;解决 1.关闭mysql服务,我的…

代码随想录算法训练营第四十八天 | 力扣 198.打家劫舍, 213.打家劫舍II, 337.打家劫舍III

198.打家劫舍 题目 198. 打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警…

word文档生成PDF文档时候自动生成书签方法

0 Preface/Foreword 在日常工作中&#xff0c;经常需要写技术文档&#xff0c;为了排版美观&#xff0c;一般会选择word&#xff0c;这样就可以生成目录。 word文件可以很方便生产PDF文档&#xff0c;方便分享给同事。 在阅读PDF文档时&#xff0c;看到有些PDF文档在左侧有一…

Kafka入门(安装和SpringBoot整合)

文章目录 一、Docker安装Kafka1. 创建网络2. 安装zookeeper3. 安装Kafka 二、Kafka介绍1. Kafka简介 三、SpringBoot整合Kafka1. 引入pom依赖2. application.propertise配置3. Hello Kafka(Producer)4. Consumer Kafka5. 带回调的生产者6. 自定义分区器7. kafka事务提交8. 指定…

如何将 O2OA (翱途) 集成到阿里钉钉

O2OA 平台拥有配套的原生开发的安卓和 IOS 移动 APP&#xff0c;可以以微应用的方式集成到阿里钉钉&#xff0c;同步钉钉的企业通讯录作为本地组织人员架构&#xff0c;并且可以将待办等通知直接推送到钉钉进行消息提醒。本篇主要介绍如何将 O2OA 集成到阿里钉钉实现钉钉办公。…

欧科云链(01499.HK)成格林威治经济论坛钻石级行业独家合作伙伴

5月30日讯&#xff0c;欧科云链控股有限公司&#xff08;“欧科云链控股”&#xff0c;1499.HK&#xff09;官宣成为全球高端经济峰会格林威治经济论坛(Greenwich Economic Forum&#xff0c;下称GEF论坛)的钻石级行业独家合作伙伴。该论坛将于6月15日至16日&#xff0c;首次在…

【维生素C语言】附录:Github 使用教学

&#x1f451; 全新Python高级软件实践专栏&#xff1a; 一起玩蛇啊 &#x1f449; 《一起玩蛇》&#x1f40d; &#x1f4ad; 写在前面&#xff1a;本章我们将介绍 Git 的基本使用方法&#xff0c;包括注册 GitHub 账号、设置 Git、创建本地存储库、复制本地存储库、导入远程…

electron24整合vite4+vue3创建跨端桌面程序

基于Electron集成Vite4.x构建桌面端exe应用 electron24-vite4-vue3 运用最新版本electron结合vite4.x创建vue3桌面端应用程序。 // 版本信息 vite: ^4.3.2 vue: ^3.2.47 electron: ^24.4.0 electron-builder: ^23.6.0创建vitevue3项目 // 初始化项目 npm create vitelatest el…

Echarts绘制K线图,文末源码地址!

文章目录 K线图Apache Echarts绘制K线图完整源码地址 本文中仅展示部分关键代码&#xff0c;文末有完整源码地址&#xff0c;欢迎下载&#xff01; K线图 K线图是一种常见的股票价格走势图表&#xff0c;它是用于显示股票价格变化的一种图表形式。K线图以日、周、月等周期为单…

聊聊分布式解决方案Saga模式

Saga模式 Saga模式使用一系列本地事务来提供事务管理&#xff0c;而一个本地事务对应一个Saga参与者&#xff0c;在Saga流程里面每一个本地事务只操作本地数据库&#xff0c;然后通过消息或事件来触发下一个本地事务&#xff0c;如果其中一个本地事务失败了&#xff0c;Saga就…

一文搞懂激活函数(Sigmoid/ReLU/LeakyReLU/PReLU/ELU)

深度学习算法之前的机器学习算法&#xff0c;并不需要对训练数据作概率统计上的假设&#xff1b;但为了让深度学习算法有更好的性能&#xff0c;需要满足的关键要素之一&#xff0c;就是&#xff1a;网络的输入数据服从特定的分布&#xff1a; 数据分布应该是零均值化的&#…

内核调试环境搭建

内核调试环境搭建 目录 经过测试好用的内核调试环境搭建过程ubuntu和linux版本 查看commit所属的内核版本查看Ubuntu版本号等信息 下载与安装内核 下载内核ubuntu更换内核手动下载并切换到指定源码用apt下载源码使用git下载对应版本 编译并安装linux内核&#xff08;使用linu…

Redis自学之路—分布式锁(四)

目录 分布式锁定义 靠谱的分布式锁具备的特征 【互斥性】 【锁超时释放】 【可重入性】 【高性能和高可用】 【安全性】 Redis分布式锁方案 一、SETNX EXPIRE 二、SETNX value值是&#xff08;系统时间过期时间&#xff09; 三、使用Lua脚本&#xff08;包含SETNXE…

【Web服务器集群】Apache网页优化

文章目录 一、Apache网页优化概述1.优化内容2.网页压缩2.1gzip概述2.2作用2.3Apache的压缩模块概述mod_gzip模块与mod_deflate模块 3.配置网页压缩功能3.1启用网页压缩功能步骤3.2具体操作步骤 4.配置网页缓存功能4.1启用网页压缩功能步骤4.2具体操作步骤 二、Apache安全优化1.…