以下为对C语言部分内容的总结和理解。内容包括:
目录
一、数据类型
数据类型是程序设计中操作对象以及操作对象之间关系和操作的描述。C语言提供的数据结构是以数据类型表示的。
1、整型
有符号基本型:[signed] int 占2个字节
有符号短整型:[signed] short [int] 占2个字节
有符号长整型:[signed] long [int] 占4个字节
无符号基本型:unsigned [int] 占2个字节
无符号短整型:unsigned short [int] 占2个字节
无符号长整型:unsigned long [int] 占4个字节
2、浮点型
单精度浮点型:float 占4个字节
双精度浮点型:double 占8个字节
3、字符型
有符号字符型:[signed] char 占1个字节
无符号字符型:unsigned char 占1个字节
4、无值类型
void(用于描述无值函数)
5、指针类型
占2个字节
6、构造类型
包括数组、结构体、联合体、枚举类型
*数据的存储
二、运算符、表达式和语句
C语言的运算符按运算时操作数的个数可以分为单目运算符、双目运算符和三目运算符。按运算符在运算时的功能可分为:算术运算符、关系运算符、逻辑运算符、位操作运算符、赋值运算符、条件运算符、逗号运算符、指针运算符、求字节数运算符、强制类型转换运算符、成员运算符、括号运算符等。
单目运算符
加法运算符 | + | 相当于数学意义上的“+” |
减法运算符 | - | 相当于数学意义上的“-” |
乘法运算符 | * | 相当于数学意义上的“*” |
除法运算符 | / | 两个整型数据相除是整型数据 |
取余运算符 | % | 两个运算对象必须是整型 |
*如%运算中有一个对象是负数,运算结果的符号和被除数相同。
双目运算符
赋值运算符 | = | 将“=”右边的值赋给左边 |
自增运算符 | ++ | |
自减运算符 | -- | |
复合赋值 | += | 例如:i+=2;等价于i=i+2; |
*自增符号在左边,先自增后赋值;自增符号在右边,先赋值后自增。
#include<stdio.h>
int main()
{
int a,b,m,n;
a = 1,b = 2;
m = (a++)+(b--)+(b++);
n = (++a)+(--b)+(++b);
printf("%d,%d",m,n);
}
运行结果为
类型转换
类型强制转换是通过类型转换运算来实现的。
表达式一般形式为:
(类型说明符) 确定的值
例如:
(int)x%5 /*把x表示的表达式的值转换为int型数据,再和5取余*/
位运算符
按位与 | & | 0&0=0 0&1=0 1&0=0 1&1=1 |
按位或 | | | 0|0=0 0|1=1 1|0=0 1|1=1 |
按位异或 | ^ | 0^0=0 0^1=1 1^0=1 1^1=0 |
按位取反 | ~ | 对参与运算二进制按位取反 |
按位左移/右移 | <</>> | 对象<</>>位数 |
逗号表达式
逗号表达式的值是最后一个操作数的值
例如:a=(3,5,7) 输出a=7,表达式值为7
a=3,5,7 输出a=3,表达式值为7
C语言运算符优先级排序(优先级高的先执行)
字符
语句
1、条件语句
if(条件)
{
语句...;
}
else 语句...;
if里面的判断若成立则返回真(1),否则返回假(0)
2、for循环语句
for(表达式1;表达式2;表达式3)
{
语句...;
}
表达式1 一般为赋值表达式,给控制变量赋初值.
表达式2一般为 关系表达式或逻辑表达式,循环控制条件.
表达式3 一般为赋值表达式,给控制变量增量或减量.
while(表达式)
{undefined
语句...;
}
do
{undefined 语句...;
}
while(表达式);
3、选择语句
switch ( 常量表达式 )
{
case 常量1 :语句;break;//每次执行完局后跳出。
case 常量2 :语句;break;
...
case 常量n:语句;break;
default :语句;break;
}
三、循环
for循环
while循环
do while循环
上程序:
#include <stdio.h>
int main()
{
int number;
int sum = 0;
int count = 0;
do
{
scanf("%d",&number);
if(number !=-1){
sum += number;
count ++;//数的个数
}
}while(number != -1);//终止循环,随便你输入,只要不在需要算的数里就OK
printf("%f\n",1.0*sum/count);
return 0;
}
这是一个计算平均数的程序,经过循环,可以计算出输入的数据的平均数。
四、分支和跳转
单分支为if语句
#include<stdio.h>
int main()
{
int a;
printf("请输入你的成绩\n");
while (scanf("%d",&a)<100)
{
if (a>0 && a<60)
printf("不及格\n");
if (a>=60 && a<80)
printf("良好\n");
if (a>=80 && a<=100)
printf("优秀\n");
return 0;
}
}
二分支为if else语句
if (关系表达式)
语句1;
else
语句2;
上程序简单解释:
#include<stdio.h>
int main()
{
int i;
printf("请输入\n");
scanf("%d",&i);
if(i>0 && i<60)
printf("不及格\t");
else if (i>=60 && i<70)
printf("及格\t");
else if (i>=80 && i<100)
printf("优秀\t");
else if (i==100)
printf("棒棒\t");
}
跳转
break和continue语句
C语言中有四种转移语句:goto语句,break语句,continue语句,return语句
goto语句是无条件转移语句,格式为“goto语句标号;”,语句标号是按标识符规定书写的符号,放在语句行的前面。但在程序中不主张用goto语句,因为会无条件使用,以免造成程序的混乱。
return是函数的返回语句。功能是计算表达式的值,并把表达式的值返回给主调函数。有值函数需要给主调函数一个返回值,用return语句实现。
break语句只能使用在switch语句的语句体和循环体语句中。作用是:结束循环,继续执行后续语句。注意
- 程序在执行到循环中的break语句时,会终止包含它的循环,并去执行下一阶段,
- break 语句位于嵌套循环内,它只会影响包含它的当前循环
#include<stdio.h>
int main()
{
float money,month;
scanf("%f",&money);
switch (month)
{
case 3:interest = money * 0.026f * (float)month / 12; break;
case 6:interest = money * 0.028f * (float)month / 12; break;
case 12:interest = money * 0.030f * (float)month / 12; break;
case 24:interest = money * 0.0375f * (float)month / 12; break;
case 36:interest = money * 0.0425f * (float)month / 12; break;
case 60:interest = money * 0.0475f * (float)month / 12; break;
default:
break;
}
}
continue语句只能使用在循环体语句中。作用是:结束本次循环,不再执行之后的语句。
#include<stdio.h>
int main()
{
int n;
for(n=1;n<1000;n++);
{
if(n%3!=0)
continue;
if(n%5!=0)
continue;
if(n%7!=0)
continue;
printf("%d",n);
}
printf("\n");
}
该程序用for循环可以改写成:
#include<stdio.h>
int main()
{
int n;
for(n=1;n<=1000;n++);
if(n%3==0)
if(n%5==0)
if(n%7==0)
printf("%d",n);
}
可以看出,执行continue语句的条件求反恰好是执行continue后其他循环体语句的条件,可以使用if语句去掉continue语句。
五、函数
C语言可以通过函数来实现程序化模块设计。函数是为了实现特定功能,按照C语言函数定义规则而编写的相对独立的程序段。函数需要先定义,后使用。
函数定义包括函数说明部分和函数体两部分。函数说明部分是函数有关信息的说明,又称函数头。包括函数类型、函数名称、形式参数的类型、名称和数量。函数体是函数功能的实现,实现函数功能的函数段应写在“{ }”内。
函数声明的作用是通知编译系统被调函数的有关信息,以便函数调用时,编译系统能够正确识别该函数,确保函数调用正常进行。
无值函数无须给主函数返回值,用户定义此类函数时应指定函数类型为“void”。无值函数函数体中可以省略return语句,若有return语句,则表达式必须为空。
例如汉诺塔问题:
#include<stdio.h>
int move(int,char,char,char);
int main()
{
int n;
char x='A',y='B',z='C';
printf("Input number:");
scanf("%d",&n);
printf("The step to moving %2d distake:\n",n);
move(n,x,y,z);
}
int move(int n,char a,char b,char c)
{
if(n>1)
{
move(n-1,a,c,b);
printf("%c-->%c\n",a,c);
move(n-1,b,a,c);
}
else
printf("%c-->%c\n",a,c);
}
函数中的变量
全局变量
全部存放在静态存储区;作用域从变量定义处开始到本程序文件末尾;生存期从程序开始执行到程序执行结束(即程序执行期间不被释放)。
静态外部变量只能在本文件中被引用。
不被static修饰的全局变量可以通过extern被外部文件引用。
局部变量
自动变量(auto变量)都存储在动态存储区中;生存期和作用域都在其所在函数内。(系统默认没有声明存储类别的局部变量为自动变量,即auto可省略)
静态局部变量(static局部变量)存储在静态存储区中;作用域在函数内;生存期从程序执行到定义该变量开始到程序执行结束。
寄存器变量(register变量)存放在CPU的寄存器中,存取效率高。(register可省略,系统自动识别使用频繁的变量,存放在寄存器中。)
形参可定义为自动变量或者寄存器变量。
六、指针
指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。
1.指针的类型
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。例如:
(1)int*ptr;//指针的类型是int*
(2)char*ptr;//指针的类型是char*
(3)int**ptr;//指针的类型是int**
(4)int(*ptr)[3];//指针的类型是int(*)[3]
(5)int*(*ptr)[4];//指针的类型是int*(*)[4]
2.指针所指向的类型
从语法上看,只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(1)int*ptr; //指针所指向的类型是int
(2)char*ptr; //指针所指向的的类型是char
(3)int**ptr; //指针所指向的的类型是int*
(4)int(*ptr)[3]; //指针所指向的的类型是int()[3]
(5)int*(*ptr)[4]; //指针所指向的的类型是int*()[4]
指向函数的指针
函数的入口地址就是其目标代码所占连续存储单元的首地址,用函数名表示。
在计算有阶乘的函数fac()如下:
#include<stdio.h>
double fac(int k)
{
int i;
double f=1;
for(i=1:i<=k;i++)
f=f*i;
return(f);
}
函数名fac代表的就是该函数的入口地址,即该函数的指针。
返回指针值的函数
指针型函数的返回值可以是指向各种类型数据的指针。
定义类型为:
类型说明符 *函数名(带类型说明的形参表列)
{函数体}
例如:
int *fun(int *p)
{
……
return(p);
}
p = 0;和p = NULL;语句说明了怎样把特殊值0赋值给指针p,这时指针的值为NULL。常量NULL在系统文件stdio.h中被定义,其值为0,将他赋给指针时代表空指针。
p = (int *) 100;使用强制类型转换(int *)来避免编译错误,表示P指向地址为100的int类型变量。不建议这样使用,一般不将绝对地址赋值给指针,NULL例外。
多级指针
二级指针就是指向指针的指针。
例如;
int **p:
说明了p是一个二级指针变量,它能指向指向int数据的指针。
七、数组
数组是相同类型数据的有序集合,由一个统一的数组名标识。数组元素的类型可以是基本类型,也可以是指针类型,还可以是任意构造类型。根据数组元素下标的个数,可以分为一维数组、二维数组和多维数组。
一维数组元素的引用
下标法引用
数组名[下标]
例如:
int a[10],i=2,j=3;
a[0]=10;
a[i+j]=20;
scanf("%d",&a[i]);
指针法引用
*(数组名+下标)
例如;
int a[10],i;
*(a+i)访问的就是数组第i个元素
指向数组元素的指针变量
指针的运算
指针的自增自减是根据它所指向的数据的具体类型来计算的。
例如:
p=a;
*p=10;
b=*p++;
语句“*p=10”的功能是将10赋值给p指向元素a[0]。语句“b=*p++”,先访问p指向的元素a[0],再赋值给变量b,再使p自增指向下一个元素a[1]。
指向变量的指针进行自增自减或者与整数进行加、减运算时没有实际意义。
指针相减结果是两个指针之间的数据个数。
二维数组
定义形式为
类型说明符 数组名[整型常量表达式1][整型常量表达式2];
例如:
int a[2][3];
定义了二维数组a,共有2行3列6个整型元素。
二维数组的引用
表示形式: 数组名[行下标][列下标]
行下标、列下标可以是常量、变量、函数或表达式。
二维数组遍历:
for(i=1;i<6;i++)
{
for(j=0;j<4;j++)
{
a[i][j]=i*j;
}
}
数组详情可以参照:
数组详情可以参照:C语言学习——数组详解_鲑鱼683的博客-CSDN博客_c语言数组
八、宏定义
宏定义的基本语法:#define 宏名 宏体
#表示是预处理命令
define是宏命令
宏名:是符合C语言变量规则的名字,一般使用大写表示
宏体:“替换文本”可以是任意常数、表达式、字符串等
预处理会在程序进行编译之前进行处理,而宏便是在预处理的时候处理的,在后面程序中使用到宏时程序会一模一样的将宏体等效替换。
宏也分为带参宏和无参宏:
①带参宏:#define MIN(x,y) x<y?x:y
②无参宏:#define PI 3.1415926
使用宏定义方便程序修改,当我们在程序中需要多次使用某一个变量的时候,把他定义成一个宏便不用同时修改多处地方了。同时可以提高程序运行效率。宏定义是在预处理期间处理的,而函数是在编译期间处理的。这个区别带来的实质差异是:宏定义最终是在调用宏的地方把宏体原地展开,而函数是在调用函数处跳转到函数中去执行,执行完后再跳转回来。带参宏和带参函数的一个重要差别就是:宏定义不会检查参数的类型,返回值也不会附带类型;而函数有明确的参数类型和返回值类型。当我们调用函数时编译器会帮我们做参数的静态类型检查,如果编译器发现我们实际传参和参数声明不同时会报警告或错误。
上程序:
#include <stdio.h>
#include <math.h>
#define PI 3.14
int main()
{
printf("2105034304*3_1*\n");
float x,y,z;
scanf("%f",&x);
if(x<-PI/2)
{
y = 2*x*x*x+3*cos(x)+5;
}
if(x>=PI/2)
{
z = x+sin(3*x);
y = sqrt(z);
}
else
{
y = pow((x-1)/(x+2) ,3) + 5*x;
}
printf("%f",y);
}
九、结构体与联合体
结构体(struct)是一个或多个变量的集合,这些变量可能为不同的类型,为了处理的方便而将这些变量组织在一个名字之下。由于结构体将一组相关变量看作一个单元而不是各自独立的实体,因此结构体有助于组织复杂的数据,特别是在大型的程序中。
共用体(union),也称为联合体,是用于(在不同时刻)保存不同类型和长度的变量,它提供了一种方式,以在单块存储区中管理不同类型的数据。
结构体类型定义的一般形式为:
struct 结构体类型名
{
类型说明符 成员名1;
类型说明符 成员名2;
……
类型说明符 成员名n;
}
定义结构体类型变量
1、先声明结构体类型,再定义变量名
结构体类型名 结构体变量名;
例如:定义一个结构体类型 struct student
,就可以用它来声明变量:
struct student student1, student2;
定义了 student1
和 student2
为 struct student
类型的变量,它们具有 struct student
类型的结构,后续我们可以对它们进行初始化。
2、在声明类型的同时定义变量
例如:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
} student1, student2;
它的作用与第一种方法相同,即定义了两个 struct student
类型的变量 student1、student2
。
3、直接定义结构体类型变量其省略了结构体名,一般形式为:
struct {
成员列表
} 变量名列表;
结构体变量的引用
引用结构体变量中成员的方式为:
结构体变量名.成员名
例如,student1.num
表示 student1
变量中 num
成员,我们可以对结构体变量的成员进行赋值:student1.num = 10010
;。
如果成员本身又属于一个结构体类型,则要用若干个成员运算符(点号 .),一级一级地找到最低一级的成员,例如:
student1.birthday.month = 9;
另外对结构体变量的成员可以像普通变量一样进行各种运算,也可以用取址运算符 & 引用结构体变量成员的地址,或者引用结构体变量的地址。
共用体变量定义一般形式为:
union 联合体类型名
{
类型说明符 成员名1;
类型说明符 成员名2;
……
类型说明符 成员名n;
}
联合体变量定义
1、先定义联合体类型,在定义联合体变量
例如:
union udata
{
int i;
char c;
float f;
};
union udata u,*p;
2、定义联合体类型同时定义联合体变量
union udata
{
int i;
char c;
float f;
} u,*p;
3、直接定义联合体变量
union
{
int i;
char c;
float f;
}u,*p;
联合体变量的引用
与结构体类似,共用体变量中成员的引用方式为:
共用体变量名.成员名
只有先定义了共用体变量才能引用它,而且不能直接引用共用体变量,只能引用共用体变量中的成员。例如,前面定义了共用体变量 a,则:
-
a.i
表示引用共用体变量中的整型变量 i -
a.c
表示引用共用体变量中的字符型变量 c -
a.f
表示引用共用体变量中的实型变量 f
但不能只引用共用体变量,例如 printf("%d", a)
; 是错误的,因为 a 的存储区有好几种类型,分别占不同长度的字节,仅写共用体变量名 a,难以使系统确定究竟输出的哪一个成员的值。
详情请见:
此次分享先到这里,下次继续。