C语言基础知识

C语言写代码步骤:

编辑,编译,执行,调试

关键字:

Include(包含)头文件包含

Int:  整形,整数类型    %d        short   短整形   long  长整形    范围不一样

Char  字符   ASCII字符 %c  数字编码表示一个符号  一般8位2进制数  无符号0~255

Float 浮点型  小数       %f   %2.10 前2为后10位     float   double  范围不一样

return 返回

编译 gcc hello.c -o hello   执行./hello

Printf();  打印输出   \n 换行   \ 接续符

有符号数和无符号数

有符号

Signed int   signed long int   signed short int

无符号

Unsigned int    unsigned long int   unsigned short int

小数没有无符号的

Signed float   signed double

Signed char         -128-127     

Unsigned char       0 ~ 255

常用运算符: + - * /  %

复合运算:(最高级,优先运算)

= 赋值运算,与数学完全不同,把右边里面的东西传到左边部分

判断运算符:== 等于  != 不等于 >大于  <小于 >= 大于等于  <=小于等于

A+=b  a+b = a

逗号运算符,主要作用是用来分割

++ --      a++  等于  ++a 等于 a= a+1  等于 a += 1  

a++后置,先运算在加一  ++a,前置,先加一在运算

代码风格:空格  空行 注释 文件头 函数头

程序结构一共有三种

顺序结构:按照实物本身特性,必须一个一个接着一个来完成

选择结构:到某个节点后,会根据一次判断结果来决定之后是走哪一个分支

循环结构:循环体,循环一段代码,关键判断循环体执行多少次

If else  bool类型,真假

If(bool值1)

{

}else if(bool值2) //开头和结尾只能有一个,中间可以有很多个

Else

{

}

//执行到这一句,变量值已经知道了

Switch case语句执行时,会用该变量的值依次与各个

Case 后的常数去对比,试图找到第一个匹配项。

找到匹配项够,就去执行该case对应的代码段

如果没有找到则继续对比下一个case,直到default

如果前面的case都未匹配,则default匹配

Switch(变量)

{

  Case 常数1:

      代码段1;

     Break;

  Case 常数2:

      代码段2;

     Break;

..........

default:

     代码段;

     Break;

}

注意:case中必须是常数,而且必须是整形(不能是float double,可以是int char)

一般来说,每个case中代码段后必须有一个break,如果没有,结果可能会让你大吃一惊

Case之后一般都会有default,语法上允许没有default,但写代码时一定要写。

Switch case和if else对比

1.if else适合对比条件比较复杂,但是分支比较少的情况,switch

 Case 适合那种对比条件不复杂,但是分支很多的情况

2.所有的选择结构,其实都可以用if else来实现。但是只有部分才可以

用switch case实现。

一般的做法是:在合适使用switch case的情况下会优先使用switch case 如果不适合使用switch case,则不得不使用if else。

循环结构三种:for循环,while循环,do while 循环

for(循环控制变量初始化;循环终止条件:循环控制变量) 三部分不可省略

{

循环体

}

For(a = 1;a<56,a++)

{

}

For循环的执行步骤

  1. 先进行循环体控制变量初始化
  2. 执行循环终止条件,如果判断结果为真,则进入第3步,如果为假则循环终止,退出
  3. 执行循环体
  4. 执行循环控制变量增量,转入第2步

基础知识:当我们定义了一个局部变量,但是没有初始化的时候,这个值是随机的。

标准的for循环,应该把循环控制变量的初始化,增量都放在()当中,并且在循环体中绝对不应该更改循环控制变量(可以引用他的值,但不应该改变它)。

For(i = 0,sum = 0,i < 10; i++)

{

    不能改变i,可以引用

sum += i;

}

While循环

I = 0                

While(i<100)

{

Printf(“hello world”);

}

While循环的执行步骤:

  1. 首先是循环初始化,这一部分其实不属于while循环本身
  2. 先判断终止条件是否满足,如果真,则进入第2步,否则直接退出
  3. 执行循环体,然后转入第1步。

I = 0  

Do

{

Printf(“hello world”);

I++;

}while(i<20);

Do while循环的执行步骤

  1. 首先是循环初始化,这一部分其实不属于do while循环本身
  2. 执行循环体
  3. 判断终止条件,若成立,则转入2;若不成立立即退出

总结:while循环和do while循环哪里不同?

While循环是先判断后执行,do while循环是先执行后判断,等循环开始返转了,其实是一样的。

While循环有没有可能循环一次都不执行         有

Do while 循环有没有可能循环体一次都不执行    不可能,至少执行一次

总结:不管那种循环结构,都不能缺少一些要素

循环控制条件初始化,终止条件,循环控制变量增量,循环体

C语言基础大模块:数据类型,运算符,三种程序结构,函数,数组,指针,结构体,共用体,枚举

函数

函数是C语言代码的基本组成部分,它是一个小的模块,整个程序由很多个独立的模块(函数)组成,这就是程序设计的基本分化方法。

Main:C语言中所谓的主函数,主函数就是一种特别的函数,特别之处在于,一个C语言程序只能有且必须有一个main函数,C语言规定,一个C语言程序从主函数开始执行,到主函数执行完结束。

Printf:函数的作用是用来在标准输出中打印信息,这个函数不是程序员自己写的,是C语言标准库提供的一个库函数,在C语言中写代码时可以引用库函数,但是必须使用#include引用这个库函数所在的头文件。

写程序也得有目标

写一个计数器,每一个功能用一个函数封装,函数定义=函数实现,然后声明,才能被调用。

使用函数来写程序时关键部分:

函数定义:函数定义是关键,是这个函数的实现,函数定义中包含了函数体,函数体中的代码段决定了这个函数的功能。

函数声明:函数声明实际上是叫函数原型声明,什么叫原型?函数的原型包含三部分,函数名,返回类型,函数参数列表。通俗讲,函数原型就是这个函数叫什么,接收什么类型的几个参数,返回一个什么样的返回值。

函数声明的作用,在于告诉使用函数的人,这个函数使用时应该传递给他什么样的参数,它会返回什么类型的返回值,这些东西都是写函数的人在函数定义中规定好的,如果使用函数的人不参照这个原型来使用,就会出错,结果就会和你想的不一样。

函数调用:函数调用就是使用函数名来调用函数完成功能,调用时必须参照函数原型给函数传参,然后从函数得到适当的返回值作为结果。

函数的参数

形参:形式参数的简称。在函数定义和函数声明中的参数列表中的参数,都是形参

实参:实际参数的简称。函数调用中,实际传递的参数才是实参。

函数调用的过程,其实就是实参传递给形参的一个过程,这个过程传递实际是一次拷贝。实际参数的时候,实参(本质是一个变量)本身并没有进入到函数内,而是把自己的值复制了一份传给了函数中的形参,在函数中参与运算,这种传参方法,就叫传值调用。

返回值:(关键字 return)

当函数执行完成之后,会给调用该函数的地方返回一个值,这个值的类型就是函数声明中返回类型,这个值就是函数体中最后一句return xxx;返回的那个值。

函数名,变量名

第一点:起名字时候不能随意,要遵守规则,这个规则有两个层次,第一层是合法,第二层合理。合法就是符号C语言中变量名的命名规则,合理就是变量名起的好,人一看就知道什么意思,一看就知道这个函数是干嘛的,而且优美,好记。

第二点:C语言中,所有的符号都是区分大小写的。

数组

到目前为止,我们已经学习了C语言的基本数据类型:整形,浮点型,字符型,再往后就是复合数据类型。

所谓复合数据类型,是指由简单数据类型,经过一定的数据结构封装,组成而成的新的数据类型。譬如数组,譬如结构体,譬如共用体

为什么需要数组?

数组就是数组成一个组,数就是一个特定的数据类型的变量,组就是说好多个数放在一起。

怎么定义数组?

Int a[4] ;    数组中元素类型  数组名【数组元素个数】;

总结:数组中的所有元素必须是同一种数据类型,不可能在一个数组中存储两种数据类型的数

怎么使用数组?

数组定义的时候作为整体定义。但是使用的时候不能作为整体使用,使用时必须拆开使用数组中的各个元素。

譬如数组int a【4】,使用其中的四个元素,分别用a【0】...a【3】,其中【】是数组的标志,【】中的数字叫做数组下标(index,索引),下标是我们访问数组中各个元素的指引,下标是0代表数组中第一个元素,下标是1代表数组第二个元素。如果数组长度为n,下标中最后一个是n-1,访问数组时要特别注意下标,下标是从0开始的,如果下标超出n-1,会产生越界访问,结果是不可预期的。

数组的初始化问题

初始化(Init),是为了让对象有一个预定的初始化状态

譬如说:

  1. 变量的初始化

当一个局部变量定义时没有初始化,它的值是随机的。这个如果没有注意,可能会导致程序出错,怎么办,解决方案有两个;

第一个,在定义过后明确给他赋值,使用=运算符

第二个,定义该变量时,同时进行初始化。

总结:一般来讲,只要你记得显示赋值,则两种方式并无优劣差异。但是人会犯错的,会不小心,所以还是定义同时初始化好一点,因为这个定义的时候就有了固定值,即使之后忘记显示赋值也不会造成结果是随机的。

一般情况下,定义的同时都将变量初始化为0,局部变量定义同时初始化为0,这是一个写代码的好习惯。

  1. 数组的初始化

第一种:完全初始化,依次赋值    int a【3】 = 【0,1,2】

第二种:不完全初始化,初始化式中值从a【0】开始,依次向后赋值,不足的默认用0 int a【3】={};或{0};

不同数据类型数组

Int a[5];       //整形数组

Float a[5];     //浮点数组

Double a[5];   //双精度浮点数组

Char a[5];     //字符数组

程序在环境运行时,需要一定的资源支持,这些资源包括,cpu(运算能力),内存等,这些资源一般由运行时环境(一般是操作系统)来提供,譬如我们在Linux系统上./a.out运行程序时,Linux系统为我们提供了运算能力和内存。

程序越大,运行时消耗的资源越多,譬如内存占用,越大的程序,占用的内存越多,占用内存的其中之一,就是我们在程序中定义变量。

c语言程序中,变量的实质就是内存中的一个格子,当我们定义(创造一个变量)

就相当于在内存中得到了一个格子,这个格子的名字就是变量名,以后访问这个内存格子就使用该变量名就行了,这就是变量的本质。

数据类型的实质是内存中格子的不同种类,譬如整形格子(类型是int),单精度浮点型格子(float),双精度浮点型格子(double),字符型格字(char)。

二进制,二进制位,字节,8个二进制位

Sizeof运算符

作用:返回一个变量或者一个数据类型的内存占用长度,以字节为单位。

Sizeof(a)/sizeof(a[0])测试一个数组中究竟有多少个元素

数据类型的实质是内存中格子的不同种类,譬如在32位机器上

短整形格子(short)          占用2字节空间16位

整形格子(int)              占用4字节空间32位

单精度浮点型(float)        占用4字节

双精度浮点型 (double)     占用8字节空间 64位

字符型格子(char)          占用1字节空间 8位

字符数组及它的两种初始化

Char a[5];

基础知识:

  1. 在C语言中引出一个单个字符时,应该用单引号‘’括起来
  2. 定义数组同时初始化,则可以省略数组定义时[]中的长度,C语言编译器会自动推论其长度,推论依据是初始化式中初始化元素的个数。由此可知,省略[]中数组元素个数只有一种情况,那就是后面的初始化式必须为完全初始化。
  3. 在C语言中引出一个字符串时,应该用“”括起来,譬如“abcde”

“abcde”实际上有6个字符,分别是‘a’‘b’‘c’‘d’‘e’‘\0’

‘\0’这个字符是ASCII码表中的第一个字符,它的编码值是0,对应的字符是空字符(不可见字符,在屏幕上看不见,没法显示,一般要用转义字符方式来显示。譬如‘\n’表示回车符,‘\0’是C语言中定义的字符串的结尾标志)。于是乎变成了6个字符。

指针

%p 打印指针指向的值

Int main(void)

{

  Int a = 23;

  Int *p;      //定义了一个int型指针变量P

  P = &a;     //p = (&a)取地址

  *p = 111;

Printf(“a = %d.\n”,a);

a = 111;

}

&:取地址符,将它加在某个变量前面,则组合后的符号代表这个变量的地址值

A 代表变量a本身

P 代表指针变量p本身

&a 代表a的地址

*p 代表指针变量p所指向的那个变量,也就是变量A

*,指针符号,指针符号在指针定义和指针操作的时候,解析方法是不同的。

Int *p; 定义指针变量p,这里的*p含义不是代表指针变量p所指向的那个变量,在定义时这里的*含义是告诉编译器p是一个指针。

指针全称是指针变量,其实质是C语言的一种变量,这种变量比较特殊,通常它的值会被默认为某个变量的地址值(p = &a),然后我们访问变量a,不必只通过a这个变量名来访问,而可以通过p = &a,*P = xxx,这样的方式来间接访问变量。

指针的定义和初始化

指针既然是一种变量,那么肯定也可以定义,也可以初始化

第一种:先定义在赋值

Int *p;

P = &a;

第二种:定义的同时初始化

Int *p = &a;

各种不同类型的指针

指针变量本质上是一个变量,指针变量的类型属于指针类型。

Int *p;定义了一个指针类型的变量p,这个p所指向的那个变量是int型。

Char *p;    p是指针变量,指向的变量是char类型

Float *P;

Double *p;

各种指针类型和它们所指向的变量类型必须匹配,否则结果不可须知。

指针定义的两种理解方法:

Int *P

第一种:首先看到p,这个是变量名,其次,p前面有个*,说明这个变量p是一个指针变量;最后,*P前面有一个int,说明这个指针变量p所指向的是一个int型数据。

Cahr *(*(*pfunc[]))(char *,char*)类似的复杂表达式,可以用相同的分析方法得到

第二种:首先看到p,这个是变量名,其次,看到p前面的int *,把int *作为一个整体来理解,int *是一种类型(复合类型),该类型表示一种指向int型数据的指针。

总结:第二种方法便于理解,但是不够本质,建议用第一种方法来理解,因为这种思维过程可以帮我们理解更复杂的表达式。

指针与数组的初步结合

数组名:做右值时,数组名表示数组的首元素地址,因此可以直接赋值给指针。

如果有int a[5];

则a和&a[0]都表示数组首元素a[0]的首地址。

注意:数组首元素的首地址和数组的首地址是不同的。前者是数组元素的地址,而后者是数组整体的地址,两个东西的含义不同,但是数值上是相同的。

根据以上,我们知道可以用一个指针指向数组的第一个元素,这样就可以用间接访问的方式去逐个访问数组中各个元素。这样访问数组就有了两种方式。

有int a[5];  int *P;  P = a;

数组的方式依次访问:a[0]  a[1]  a[2]   a[3]  a[4]

指针的方式依次访问:*P   *(P+1) *(P+2) *(P+3) *(P+4)

指针与++ -- 符号进行运算

指针本身也是一种变量,因此也可以进行运算,但是因为指针变量本身存在的是某个其他变量的地址值,因此该值进行* /

%等运算是无意义的,两个指针变量相加本身也无意义,相减有意义。指针变量+1,-1是有意义的。+1就代表指针所指向的格子向后挪一格,-1代表指针所指向的格子向前挪一格。

*P++ 就相当于*(P++),P先与++结合,然后P++整体再与*结合

*P++解析,++先跟P结合,但是因为++后置的时候,本身含义就是先运算后增加1(运算指的是P++整体与前面的*进行运算;增加1指的是P+1),所以实际上*P++符号整体对外表现的值是*P的值,运算完成之后再加1

所以*P++等同于*P  P+=1;

*++P等同于 P += 1; *P;

(*P)++,使用()强制将*与P结合,只能先计算*P,然后对*P整体的值++。

++(*P),先*P取值,再前置++,该值+1后作为整个表达式的值。

总结:++符号和指针结合,总共有以上4种情况。--与++的情况很类似。

函数传参中使用指针

Int add(int a,int b)函数传参使用了int型数,本身是数值类型。实际调用该函数时,实参将自己拷贝一份,并将拷贝传递给形参进行运算,实参自己实际是不参与的。

所以,在函数中,是没法改变实参本身的。

结构体,共用体,枚举,宏定义,预处理

结构体

为什么需要结构体?什么是结构体?

没有结构体之前,C语言的数据依靠:变量+数组。最初最简单的时候,只需要使用基本数据类型(int char float double)来定义单个变量,需要几个变量就定义几个。

后来情况变复杂了,有时需要很多意义相关的变量(譬如需要存储及运算一个班级的学生分数)这时候数组出现了。数组解决了需要很多类型相同,意义相关的变量的问题。

但是数组是有限制的。数组最大的不足在于,一个数组只能存储很多个数据类型相同的变量。

所以碰到需要封装几个类型不同的变量的时候,数组就无能为力。

譬如对应题目:使用一个数据结构来保存一个学生的所有信息:姓名 学号 性别

这个时候就需要结构体

什么是结构体

结构体其实就是一个集合,这个集合里面包含很多个元素,这些元素的数据类型可以相同,也可以不相同,所以结构体是一种数据封装的方法。结构体存在的意义就在于把很多数据类型不相同的变量封装在一起,组成一个大的新的数据类型。

数据结构:把庞大复杂的数据用一定的方式组织起来,便于操作(查找,增加,删除等)这就叫数据结构。

结构体与数组的关联:数组是一种特殊的结构体,特殊之处在于封装内的各个元素类型是相同的。结构体和数组都是对一些元素封装,因此定义的时候都是封装作为整体定义,但是使用的时候,都是使用封装中的子元素。一般结构体变量和数组变量都不会作为一个整体操作。

使用结构体的步骤:

第一步:定义结构体类型。结构体类型的定义是在函数外面(函数外面 == 全局)的

第二步:使用第一步定义的类型定义结构体变量。

第三步:使用变量,实际上使用结构体变量的时候,使用的是结构体变量中封装的各个子元素,而不是结构体变量本身。

结构体的初始化

结构体变量和普通变量一样,作为局部变量时,如果定义的时候无初始化也无显示赋值,则结构体变量中的子元素的值是随机的。

发现2种C语言接受的结构体初始化方式。

第一种,完全初始化。{xx,xx,xx,xx,xx}

第二种,部分初始化。

{

 .a = xx,

.b = xx,

.c = xx,

.d = xx,

};

新增关键字:struct

新增字符操作:.

基础知识:

  1. double float用%f打印,char用%c或%d打印,int用%d,字符串用%s打印,指针用%p打印

共用体(union联合,联合体)

  1. 共用体union在定义和使用形式上,和结构体struct很相似。但是两种数据结构是完全不同的两类东西。

结构体,是对多个数据的组合与封装

共用体,共用体中只有一个东西,只是它被好几个名字(和类型)共用。

Char  -128~127

Int   xxx -xxx

宏定义

#define   N   321   //宏定义格式

宏定义要注意的问题;

  1. 宏定义一般是在函数的外面
  2. 宏定义必须要先定义,再去使用宏,如果先使用就会编译报错
  3. 宏定义中宏一般用大写

为什么使用宏定义?

在C语言中,一般使用常数的时候,都不是直接使用,而是先把该常数定义为一个宏,然后在程序中使用该宏名。这样做的好处是,等我们需要修改这个常数时,只需要在宏定义处修改一次即可,而不用到代码中到处去寻找,看哪里都用过该常数。

枚举

Enum week'

{

 Sun      0

Mon      1

Tue       2

Wen      3

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值