C语言学习

C语言学习

day1

1、一些零碎知识点:

运行环境 VC++ 2010,记得修改字体和添加命令“运行(但不调试)”,显示行号等等

创建完工程之后需要修改主代码文件后缀为“.c”

写完代码怎么运行??
C的代码写完后需要"编译"生成.obj文件和一些相应的库文件,之后点击"连接",即可把obj和库函数关联起来,生成一个可执行文件.exe

快捷键配置:工具>选项>键盘>注释

2、代码格式化,一键注释等。

day2

1、变量

我们定义一个变量,其实就是在计算机内存中使用了一部分空间,变量就指向该空间里储存的数据

变量本身也需要内存,所以它有一个指针

2、printf注意事项

a.对应int、double(float)、char等数据类型,对应%d、%.xf(默认保留小数点后6位)、%c or %s

&注意:

C语言中,根据数据的功能和所占内存大小,共分为以下几种数据类型:基本类型、构造类型、指针类型和空类型(void)

数据所占内存却决于计算机的编译器、操作系统系统位数

以计算机二级考试所用和windows 为例

win32						 字节数
char、unsigned char 			  1
short、unshort				  2
int、unsigned				  4
long、unsigned longlong int   4 
float						   4
doublelong double            8

win32字节数
char、unsigned char1
short、unshort2
int、unsigned4
long、unsigned long、long int4
float4
double、long double8

2.1 整形、浮点型数据类型

浮点型数据可以定义字符或者字符串,注意:转义字符为一个字符,如:\n

2.2 布尔类型boolean

C89标准中没有定义boolean,一般半段真假的时候通过0和1

我们可以通过宏定义

#define TRUE 1

#define FALSE 0

C99标准则定义了宏定义,需要导入<stdbool.h>

2.3数据类型转换

· 如果是混合数据运算,则有限转化为精度最高的数据类型,然后在进行运算

· 如果是强制转换(精度高—精度低),则是截断而非四舍五入float a = (float)b

2.4 指针入门

C语言中,数据是存储在计算机的内存空间之中的。而字节(1 Byte=8 bit)作为计算机的最小存储单元,许多字节就组成了计算机的内存空间。为了让计算机区分出不同的内存空间,我们给这些空间进行了编号,这种编号就是指针值,也叫做地址。所以每一个指针都对应有各自的内存空间,这些内存空间里就储存了我们需要的数据。

所以要理清一个概念,无论什么类型的数据,只要是计算机需要使用到的,都需要占用一定的内存。

那么,他就有属于它自己的指针。

C中定义了关于指针的几种操作:

1、指针变量 int *p,float *p等,该变量可以存储指针

2、取指针:通过 ‘&’ 符号,得到某个变量的指针

3、解指针:通过 ‘*’ 符号,得到某指针变量所指向的内存空间里的值。即得到某指针指向的值

2.5 值传递和地址传递

1、我们的基本数据类型、结构体等都是传值传递——本质是拷贝内容给接受变量,不会改变输入的值

2、地址传递需要注意,由于传递的是地址,而地址往往与它所对应的内存空间有关。所以这种操作是可以改变变量的值的。

2.6 常量

恒为常数,不可修改

定义有两种方法

#define xx xx  ————#undefine xx
const 类型 xx;
define与const差别:
define定义不带类型,没有类型检查,可能会造成边界效应(截断)
define是一个简单的替换,,没有数学的组合效果(括号) 

2.7 运算符

1、算数运算符

自加&减运算符:++、–

需要注意赋值的时候,++i是先自加在赋值,i++是赋值后在自加

如果是独立使用,则++i和i++等价

2、关系运算符

==、!=、<、>、>=、<=

运算结果用真(1)和假(0)表示

与、或,分别对应:&&、||、!

&&:短路现象(又叫逻辑短路)

3、赋值运算符

+= 、-=、 /=

位运算符

4、三元运算符

表达式1?表达式2:表达式3

if 1式为真,执行式2

else 式3

2.8 运算符优先级

逗号的优先级最低,其余的可查看资料

2.9 变量命名规范

常量全大写,变量不能以数字开头(结合字母、数字、下划线),但是也要注意不能与一些关键字重名!

day3

1、程序结构:顺序结构,选择(分支)结构,循环结构

分支结构:单分支,多分支——通过if和switch语句实现

循环结构:通过for和while语句实现

for循环——先赋值,执行一次循环体,在判断,然后执行最后一个冒号后的语句

注意:for循环里的循环变量的内存空间的位置是一直不变的,程序只是根据循环的需要,修改该内存空间里的值

while循环——先判断,如果判断为真,执行循环体。

do—while——先执行一次再判断。

for与dowhile循环都是先判断在执行,区别是前者知道循环次数,后者可以不用知道

可以嵌套

注:还有go to语句,这个语句需要定义标签,一般在程序中,为了避免程序混乱,不建议采用

2、枚举

枚举是C的一种构造数据类型

enum Day//构造枚举类型,创建枚举元素
{
    mon=1,tue=2,wed=3;
};//注意这里要加分号

enum Day day //定义生成一个枚举变量,变量可以通过印用枚举元素从而获取里面的值
    
    //上面可以合成一句话
enum Day
{
    mon=1,tue=2,wed=3;
}day;

枚举的处是:当需要使用到的自定义数据比较多的时候,可以减少代码的书写量,并且提到可读性

如:我们前面define的布尔类型,假设这种类型不仅仅两个元素的(0和1),而是比较多的时候,就可以考虑枚举。

3、函数

3.1函数的简单语法:

返回类型 函数名称(输入参数如果没有也可以写void或者不写){
    函数体...
        ...
        ..
        return xxx; //返回值
}
//如果所需要构建的函数没有返回值,我们可以使用void
void 返回类型 函数名称(输入参数){
    函数体...
        ...
        ..
}

函数每次执行都会开辟一个函数栈,递归也是这个道理。相当于每调用一次函数,就开辟一个新的函数栈,栈是C里程序运行的一种内存储存形式。程序运行是一种压栈运行,main主函数叫做主栈,这些栈里面储存了程序运行所需要的数据。当函数执行完毕后,栈自动销毁

~值转递和引用(地址、指针)传递:

引用传递一般是[数组]和[指针]

3.2 头文件引用

头文件构造:

需要一个.h文件和一个.c文件,他们的名字一般相同

操作是:在.h文件里声明函数,在.c文件里构造具体的函数

#include< >、#include" "两者区别

前者应用C自带库路径里的库,后者引用.c文件相对路径里的库——一般我们使用自定义库都是用后者的写法。

3.3 变量初始化

为了避免出现内存的不必要占用和变量引用时发生异常,我们要养成初始化变量的好习惯

其中整形、浮点型变量初始化为00.0

如果是指针(point)则初始化为NULL

day4

1、计算机内存分布

计算机内存可以分为以下几个部分

内存区功能
栈区存储局部变量
堆区存储malloc函数动态分配的数据
静态区存储全局变量和静态数据
代码区储存代码/指令

2、static关键字

静态变量只初始化一次,之后数据就存储在静态区。静态区的特性使得它不会跟局部变量随着函数的结束而销毁,而是类似于全局变量,可以多次调用和修改它的值。

所以静态变量的作用域是在本程序文件的生命周期中。它与其他普通全局变量的区别是:普通全局变量可以通过exterm函数在另外一个程序里引用,而static变量则不可以。

优势:

//若要在其他程序文件里引用另一文件里的函数或者变量,使用extern声明

作用于全局变量:有效降低模块间的耦合

作用于局部变量:赋予全局性质,延长局部变量的生命周期,保留它所指向的值。

我们可以把static声明的数据看作是私有化,即:只有本程序文件可以引用而其他程序文件不能引用

3、一些常用的函数

3.1字符串函数

#include<string.h>

strlen()——返回字符串长度

strcpy(* a,* b)——覆盖性拷贝b到a

strcat(* a,* b)——字符串连接

3.2日期、时间函数

#include<time.h>

time_t curtime;time(&curtime)—时间初始化

ctime(&curtime)——返回一个表示当地时间的字符串 包括时间和日期

difftime(time1,time2)——统计两个时间点之差

3.3 常用的数学函数

#include<math.h>

pow(x,y)——返回x的平方根
sqrt(x,y)——返回x的开y次方
fabs(x)——返回x的绝对值

4、 基本数据类型和字符串类型的转换

C中用字符数组表示字符串

4.1基本数据类型转换为字符串

sprintf(str,"%d ",a)——可以将结果存放在字符串中

%8.2f:表示共八位+小数点后2位,不够用空格填补

4.2字符串转换为基本数据类型

#include<std.h>

atoi(str)——转换函数(整数)

atof(str)——转换函数(小数)

5、预处理命令和宏定义

5.1 预处理:在编译开始之前对源文件进行一些简单的操作

作用:便于程序的调试、修改,代码的跨平台使用和程序模块化

if __win32

#include<windows.h>

elseif linux

#include<linux.h>

5.2 宏定义:#define xx xx——一种字符串定义,实质是一种简单的替换

#define UINT unsigned int
#undef XXX xxx

宏定义和typedef都可以对数据类型进行重新定义,区别是前者是在编译器编译前处理,后者是编译器处理。

宏定义也可以带参数

#define MAX(a,b)(a>b)?a:b——传入的是形参
//注意:MAX于参数之间不要带空格,这样会让程序认为这个宏定义是无参形式
//宏定义中,形参不必声明数据类型,因为形参无需被分配内存,但是在调用时需要有明确的数据类型

5.3 函数与带参数宏定义的区别:

时刻注意宏定义是一种简单的替换,这里面会导致一些参数被重复引用并进行修改等问题

6、数组

数据类型:构造类型

6.1 定义数组

int、char、double(数据类型)+[n]

sizeof()——获取数组的总大小

int a[3];

a_Len = sizeof(a)/size(int);——返回a数组的长度

6.2 数组与内存

· 数组名就代表该数组的首地址

· 数组里面每个元素的内存空间时连续分布的:地址以十六进制表示,地址+字节数,以此类推

6.3 数组使用的注意事项

//注意数组名代表的是数组第一个元素的地址,所以我们在函数中传递数组名的时候,实际是传递该数组的首元素地址。由于这个原因,函数中关于数组的操作就是引用传递,相应的一些操作就会修改数组元素里的值。
//array[n]——引用数组某元素地址所对应的内存空间里储存的值

7、字符数组和字符串

C中使用字符数组来存储字符串,字符串用“ ”表示,注意单引号可以提取ASCII码,是整形变量

所以字符数组和字符串都是以”\0“结尾的


char ary1[] = {'a','b','c'};//没有指定结束标志'\0',会导致乱码
char ary2[3] = {'a','b','c'};//没有指定结束标志'\0',会导致乱码
char ary4[] = {'a','b','c','\0'};
char *ary3 = "abc";

printf("%s\n%s\n%s\n%s",ary1,ary2,ary3,ary4);

//一些难点
char str[10];
//str = "Hello!";//这里会报错,原因是:str是字符数组名,它本身表示的是字符串首元素的地址,是一个常量,不可修改。类似于int i=1这里的1
//而"Hello"其实已经是一个数组了,它表示一串内存空间(地址),所以要实现上述的功能,我们可以采取指针变量赋值的方法
	

8、debug

鼠标单击设置断点

F5开始调试、跳到下一个断点

F10 逐过程执行

F11 逐语句(进入函数体)shift+F11迅速执行完毕并跳出该函数

day5

1、指针(piont)

C语言之精华

代表内存空间的编号

//指针定义:
int *p;
char *p;
...
    
//指针操作
指针的加减都指的是字节运算,因为指针是16进制,一个字节是8(2^8)
++--//这里的自加和自减指的是单位运算,即int类型指针++等于该指针加一个int的字节(4字节)
*解指针符、&取指针符
//数组名本身就是该数组首元素的指针,并且数组内个元素的指针是连续分布的(以自身元素大小为单位)

2、指针数组

int *p[3];
顾名思义指针数组里面每一个元素都是一个指针变量.

3、多重指针(指针套娃)

前面说到,无论是指针变量还是其他变量,都需要占用计算机一定的内存,它们都有各自占用空间的内存编号(指针),于是就出现了多重指针来表示指针变量的内存编号。即:指向指针的指针

int **p;
int ***p;
使用方式与指针类似,不同的是 对于多重指针,解指针*返回的仍是指针值

4、指针函数

int 函数名(参数1,参数2)		//定义普通函数
int *函数名(参数1,参数2)		//定义指针函数

作用:可以返回指针(地址)。

注意:指针函数里的局部变量地址是不能够返回的,这是因为函数栈的特性。如果有这方面的需要,我们可以通过将局部变量定义为静态变量static,将其储存在静态区而不会随着函数的结束而被销毁。这样就能够返回局部变量的地址。

局部数据被销毁并不是指他们被清零,而是程序放弃对这块内存的使用权限,后面的代码可以使用该块内存。所以有的时候如果是两片代码使用了同一块内存,可能会出现意想不到的结果。

5、函数指针

需要预先指明返回的指针类型,否则默认返回void型指针,这种指针不指向我们定义的变量、函数等数据(没啥用)
int (*指针名)(参数1,参数2)//有参
int (*指针名)(void)//无参

函数与变量等数据类似,也是需要占用一定内存的,函数指针可以返回代码区中函数栈的首地址,我们可以通过这种方法引用函数。

//使用方法
(*指针名)(参数1,参数2

6、回调函数

在某一个函数里面调用了其他的函数,这个被调用的函数称为回调函数。可以通过调用函数指针的方式实现

void initArray(int  *array,int arraySize,int(*f)(void))
{函数体 ...
    ...
    ...
}
//这里int(*f)(void)说明需要传入一个函数指针的参数,这就是回调函数的实现方法
//所以我们就可以定义我们需要的回调函数,在把它的指针传进另外一个函数之中

7、动态内存分配

对于一些临时使用的数据,我们可以建立动态内存分配区域,在一个名为“堆”的区域里合理的安排他们的大小,并在不需要的时候即使释放

注意:在堆中申请的空间里储存的数据,由于没有跟其他变量在外部特意声明,故只能通过指针来引用

7.1 动态内存分配相关函数

#include<stdlib.h>
1malloc(内存大小(字节数))			//分配一个所需大小的空间
2calloc(n,内存大小(字节数))			//分配n个所需大小的连续空间,可以用于数组储存
3、free()							 //释放内存
4realloc(void *p,内存大小(字节数))  //调整已分配大小的空间

void *p——可以获取到一些数据的地址,称为无类型指针变量,但感觉没什么用,也不能指向地址里存储的值

8、结构体和共用体

struct Cat{
    定义所需数据类型(成员)
    char *p;
    int i;
    ...
}					//类似于python中类属性的声明
//写法1:
struct Cat cat1;
struct Cat cat2;    //声明结构体变量,类似于类的实例化

//写法2:
struct Cat cat1,cat2;

//写法3:
struct Cat{
    定义所需数据类型
    char *p;
    int i;
    ...
}cat1,cat2;

//写法4(不建议,这个只适合所需结构体变量有限的情况):
struct {
    定义所需数据类型
    char *p;
    int i;
    ...
}cat1,cat2;

// ******************************** //
cat1.p = xxx;
cat1.i = xxx;

一些习惯:正如宏定义全部大写一样,结构体构造的时候一般是首字母大写

例子:PDF 321页案例

8、共用体(联合体、Union)

8.1 结构体的每个成员(属性)占用不同内存,彼此之间没有影响

而共用体则会相互影响,优点是可以减少内存占用

union data{
    int n;
    char ch;
    double f;
    ....
}
union data a,b,c;
// 它的使用方法与结构体类似!!

//可以与结构体结合使用,减少内存占用
struct Cat{
    定义所需数据类型(成员)
    char *p;
    int i;
    ...
    union data{
    int n;
    char ch;
    double f;
    ....}data1;
}cat1;    
        
}					

8.2 共用体的内存布局

共用体里面所有成员共享内存空间,所占内存以占用内存最大的数据类型为准

内存分布是从低位到高位,以字节为单位连续分布。每个字节(最小内存单元)里面存储不同的值。每个成员根据自己占用的内存大小引用不同字节里面的数据,所以彼此的数据会相互影响

​ (Aweo 2021.09.21)

  • //
    cat1.p = xxx;
    cat1.i = xxx;

**一些习惯:正如宏定义全部大写一样,结构体构造的时候一般是首字母大写**

例子:PDF 321页案例



### 8、共用体(联合体、Union)

8.1 结构体的每个成员(属性)占用不同内存,彼此之间没有影响

而共用体则会相互影响,优点是可以减少**内存占用**

```c
union data{
    int n;
    char ch;
    double f;
    ....
}
union data a,b,c;
// 它的使用方法与结构体类似!!

//可以与结构体结合使用,减少内存占用
struct Cat{
    定义所需数据类型(成员)
    char *p;
    int i;
    ...
    union data{
    int n;
    char ch;
    double f;
    ....}data1;
}cat1;    
        
}					

8.2 共用体的内存布局

共用体里面所有成员共享内存空间,所占内存以占用内存最大的数据类型为准

内存分布是从低位到高位,以字节为单位连续分布。每个字节(最小内存单元)里面存储不同的值。每个成员根据自己占用的内存大小引用不同字节里面的数据,所以彼此的数据会相互影响

​ (Aweo 2021.09.21)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值