C语言是一门编程语言,在大学中很多专业都会学习,考研中部分专业会有涉及,工作中也仍有应用。
以下是chatgpt对c语言的简单介绍:
C语言是一种广泛应用于系统编程和应用程序开发的高级编程语言。以下是对C语言的简单介绍:
发展历史:C语言由贝尔实验室的Dennis Ritchie在20世纪70年代初开发而成。它是基于早期的B语言,并在其基础上进行了改进和扩展。
特点和优势:
- 简洁而高效:C语言提供了简洁而高效的语法结构,使得程序编写和阅读相对容易。它具有较少的语法规则和关键字,使得程序员可以更自由地控制代码的行为。
- 高度可移植性:C语言编写的程序可以在不同的计算机平台上进行编译和运行,具有较高的可移植性。这使得C语言成为系统级编程和跨平台开发的首选语言之一。
- 强大的底层控制能力:C语言提供了丰富的底层控制能力,可以直接访问内存和硬件资源。这使得C语言在系统编程、驱动程序开发和嵌入式系统等领域得到广泛应用。
- 丰富的函数库:C语言拥有丰富的标准函数库和第三方函数库,可以方便地进行各种操作,如文件处理、字符串处理、数学计算等。
应用领域:C语言广泛应用于系统编程、嵌入式系统开发、驱动程序开发、操作系统开发等领域。它也是其他高级编程语言(如C++、Java等)的基础语言。
需要注意的是,C语言相对较底层,需要程序员自行管理内存和资源,因此对于初学者来说可能有一定的学习曲线。但掌握C语言的基础知识可以为后续学习其他编程语言打下坚实的基础。
编写程序的目的是处理数据,所以先要了解数据。计算机中的数据不同于我们数学课上写的数可以随意表示任何数据,计算机中的整数和小数是不一样的,它们属于不同的类型:计算中的数据是有类型的。
数据类型四大类:基本类型、构造类型、指针类型、空类型
C语言中的常量、变量、表达式、函数都可以理解为数据。
常量有四类:整型常量、实型常量、字符型常量、字符串常量。
变量使用规则:先定义后使用
定义格式:数据类型名 变量名列表;
比如:
int i;int j;int k;
int i, j, k;
int i=1, j=1, k=9; /*赋初值*/
注:
各种表达式
定义:表达式:用运算符将数据连接起来的合法式子
运算符:三个属性:功能、优先级、结合性(运算方向(左->右 or 左<-右))
如:
3.5 + 1/2 3.5 + (1/2)
1+2+3 (3.5 * 1)/ 2 = 1.75
1.0/2 = ? 1/2 = ?
+ - * / % 【结合性是 左->右】
取余(%):
赋值运算符:= 【14级 左<-右】
格式:变量名=表达式
赋值运算符的功能:将表达式的值赋给“=”左边的变量
例如:A = 5+8 【先计算,后赋值】
a=b=c=1+2的计算顺序是a=(b=(c=(1+2))) 【表达式的值赋值给变量】
注:
例1. 若有int a = 5,b=8; 则下列表达式的值是多少?用完表达式后变量a和b的值分别为多少?
a+=b/=a
表达式的值:
A的值:
B的值:
自增运算符:++ i++ ++i
自减运算符:-- i-- --i
如:
i++; ++i; 等价于:i=i+1
i–; --i; 等价于:i=i-1
【自增自减运算符:结合性2:左<-右,优先级2级】
注:
(1)只能用于变量不能用字啊常量或表达式。
如 3++、(a+b)++ 不合法的表达式
如 int a=3; 则表达式的值 变量的值
a)a++ ?3 ?4
b)++a ?4 ?4
c)a-- ?3 ?2
d)–a ?2 ?2
题1. int a=3;求a++*a
#include
int main()
{
int a = 3;
int b= a++*a;
printf("a=%d\n", a);
printf("b=%d\n",b);
return 0;
}
题2. 若有定义int a=20,b=20,c=20,d=20;则下列表达式的值分别为多少?
A、a++ * 10
B、10 * b++
C、++c / 7
格式:表达式1,表达式2,表达式3,……,表达式n;
功能:逗号表达式的值就是表达式n的值,求值顺序是从左到右依次求解。
强制类型转换(显示转换)就是手动编写代码强制性地修改数据类型。
格式:
(类型名) 表达式
或 (类型名) (表达式)
利用强制类型转换运算符可将一个表达式的值转换成指定的类型。
如:
float x = 123.456,y;
(1) int(x) 错
(2) (int) x (int)(x)
(3) (int)x+y (int)(x+y)
进行强制类型转换,得到的是一个中间值,而原来表达式或变量的类型未发生改变。
如:
若变量x为int类型,则表达式(float)x的结果是一个单精度类型,但是x还是int型。
隐式类型转换(隐式转换)就是自动修改数据类型,一般是高精度的数据赋值给低精度的数据会出现隐式类型转换。
【隐式转换是自动完成的】
1.0/2=? 1/2=?
说明:
同一优先级的运算符,运算次序由结合方向所决定。
简单记就是:!>算术运算符 > 关系运算符 > && > || > 赋值运算符
函数(标准函数 自定义函数)
#include
// |-5| 如何表示?abs()
abs(-5)
标识符就是名字。这类名字分为三类,一类是关键字,一类是预定义标识符(库函数名等),一类是用户自定义标识符(函数名、变量名)。
C语言语句:三类语句
类型1 -> /**/
类型2 -> 定义语句;
类型3 -> 执行语句;
定义:从main()开始,由上往下一条一条地执行。
三大类语句(注释、定义、执行)->执行语句有5类:
顺序结构伪代码:就是第一步干什么,第二步干什么,下一步干什么…
例如:某同学3门功课的平均分? 是顺序结构
顺序结构的程序设计框架:#include <> int main() { 输入 76 89 92 //第一步 计算 //第二步 输出 //第三步 return 0; }
以下是chatgpt对顺序结构的解释:
在C语言中,顺序结构是一种基本的程序控制结构,它按照代码的顺序依次执行每个语句,没有任何条件或循环的控制。顺序结构是C语言程序中最简单、最基础的结构,也是程序的默认执行方式。
顺序结构的特点是代码按照从上到下的顺序依次执行,每个语句的执行不受其他因素的影响。当程序执行到一个语句时,会顺序执行该语句,然后继续执行下一个语句,直到程序结束。
以下是一个简单的顺序结构示例:
#include
int main() { int a = 10; int b = 20; int sum = a + b; // 第一条语句 printf("The sum is: %d\n", sum); // 第二条语句 return 0; // 第三条语句 } 在上述示例中,程序按照从上到下的顺序执行。首先,声明并初始化变量a和b,然后计算它们的和并将结果存储在变量sum中。接下来,使用printf函数打印出sum的值。最后,使用return语句结束程序的执行。
顺序结构在C语言中非常常见,它使得程序可以按照预定的顺序执行各个语句,从而实现特定的功能和逻辑。
“标准输入输出函数”是以一些库函数来实现的
注意:标准函数/库函数使用前必须:#include<头文件名>再包含的程序文件中最顶部。
printf():“占位符”是以%开始的,被替换。
占位符字符:
在C语言中,printf函数是一个用于输出格式化字符串的函数,它可以将指定的数据以指定的格式打印到标准输出(通常是终端窗口)。printf函数属于stdio.h头文件中的标准库函数,因此在使用之前需要包含该头文件。
printf函数的基本语法如下:
#include
int printf(const char *format, ...); 其中,format是一个字符串参数,用于指定输出的格式。…表示可变参数列表,用于指定要输出的数据。
printf函数的使用方法如下:
在程序中包含
头文件。 在需要使用printf函数的地方,调用该函数并传入相应的参数。
在format字符串中,可以使用占位符来指定输出的格式,例如:%d表示输出整数,%f表示输出浮点数,%s表示输出字符串等。
以下是一个简单的示例,演示了如何使用printf函数输出不同类型的数据:
#include
int main() { int num = 10; float pi = 3.14; char str[] = "Hello, World!"; printf("The value of num is: %d\n", num); printf("The value of pi is: %f\n", pi); printf("The string is: %s\n", str); return 0; } 在上述示例中,我们使用printf函数分别输出了一个整数、一个浮点数和一个字符串。通过在format字符串中使用相应的占位符,我们可以指定输出的格式,并将要输出的数据作为参数传递给printf函数。
运行上述程序,将会输出以下结果:
The value of num is: 10 The value of pi is: 3.140000 The string is: Hello, World!
注意,printf函数中的format字符串中的占位符必须与传递给printf函数的参数类型匹配,否则可能会导致输出结果不正确或程序崩溃。
考点1:“普通/占位符”,输入时普通字符必须原样输入。
int a, b;
scanf("%d,%d", &a, &b);
//输入:3,5
scanf("a=%d,b=%d",&a,&b);
scanf("%d",&a);//编码时常写这种
考点2:“占位符”,输入时4种输入格式。
int a,b;
scanf("%d%d", &a, &b);
//输入时,中间用空格或tab间隔或回车,最后是回车
//方式一:空格 方式二:tab 方式三:空格tab 方式四 回车
考点3:“占位符”,输入时1种输入。
char ch1,ch2;
scanf("%c%c", &ch1, &ch2);
//输入时,只能挨着输入,chr1输入后不能写空格
都是字符就需要连续输入字符
考点4:“占位符”,输入时一种输入。
char ch1, ch2;
int x;
scanf("%c%d%c", &ch1, &x, &ch2);
//输入时,数字前可有空格。如:"a 3b"
//实践:输入时,数字前可有空格或tab或回车。数字后必须直接跟字符。
考点5、地址列表,输入时&。
int x;
scanf("%d",x);//错误 or 正确
(1)putchar()
格式:putchar(字符常量或字符变量)
功能:输出一个字符但不输出单引号。
如:
putchar('a'); //a
putchar('\n');
putchar(100); //d
putchar('100');//错误
(2)getchar()
功能:接收一个从键盘输入的字符。
注:getchar()没有任何参数,函数的返回值就是输入的字符
如:
char a,b;
a=getchar();
b=getchar();
若输入为:1<回车>
则变量a的值为字符 ‘1’,变量b的值为回车符。
构成单个条件、联合多个条件。
< <= > >= == !=
三要素:功能、优先级(6级)、结合性(左->右)
关系表达式的结果是一个逻辑值(0和1,代表真假)
> 4>5
> 5==5
> 7=7
> 1<2<3
> 5>4>3
&& || !
在C语言中,逻辑表达式的值只有 1 和 0 两种值。其中,1表示“真”,0表示“假”。
&& 11级 左 —> 右
|| 12级 左 —> 右
! 2级 左 <— 右
//例题:
> 5||5
> 4<3&&9
> 0&&7
> 5>4>3&&3
做题时要考虑:
格式1:
if(表达式)
语句序列;
后续语句;
格式2:
if(表达式)
语句序列1;
else
语句序列2;
后续语句;
格式3:
if(表达式)
if(表达式)
语句序列11;
else
语句序列12;
else
语句序列2;
后续语句;
格式:
switch(表达式)
{
case 常量表达式1 : 语句序列1;
case 常量表达式2 : 语句序列2;
……
case 常量表达式n : 语句序列n;
default : 语句序列n+1;
}
case 'A':
case 'B':
case 'C':printf("CCC\n");break;
1、循环语句
功能:重复执行相同的代码段。
有三格式
while(表达式)
{
//循环体语句序列;
}
//后续语句:
do
{
//循环体语句序列
}while(表达式);
//后续语句;
for(i=0; ; i++)
{
//循环体语句;
if(i == 35){
break;
}
printf("123");
}
//后续语句
exp1一般是定义并初始化循环变量。循环在最初执行一次,只执行一次
exp2一般是是条件判断语句
exp3一般是循环的条件变量的增量(增加或减少)
for执行流程:最初执行一次并只执行一次exp1,然后 exp2->循环体语句->exp3 往复执行。若exp2为假则跳出循环,为真继续循环。
思考:若是没有exp2怎么办?相当于是1,永真,就是死循环。
例题:1+2+3+4+……+100
#include
int main()
{
int i,sum=0;
//while
// i = 1;
// while(i<=100){
// //sum += i;
// sum = sum +i;
// i++;
// }
// for(i=1; i<=100; i++){
// sum += i; //sum = sum +i;
// }
// printf("%d\n", sum);
do{
sum += i;
i++;
}while(1);
//scanf("%d", &i);
return 0;
}
格式:break;
功能:中止退出。范围:循环体中和switch体中。
for(i=1; i<4; i++)
{
i++;
break;
}
printf("%d", i);
格式:continue;
功能:结束当前本轮循环直接进行下一轮循环。
范围:循环体中。
for(i=1; i<=10; i++)
{
//i++;
if(i==6 || i==5){
continue;
}
sum += i;
//.....
}
printf("%d", i);//5
如果循环体中的continue前后都有代码,那么如果执行到continue,就相当于只跳过了循环体的后半部分。如下:
for(i=1; i<4; i++)
{
i++;
continue;
i++;
}
以下程序的运行结果是:15 or 20 or 25 or 30
#include
int main()
{
int i,j,m;
for(i=5; i>=1; i--)
{
m = 0;
for(j=i; j<=5; j++)
{
m = m + i*j;
}
}
printf("%d\n",m);
}
以下程序的运行结果是:20 or 21 or 32 or 43
#include
int main()
{
int n = 4;
while(n--);
printf("%d", --n);
}
以下程序的运行结果是?
#include
int main()
{
int i = 5;
do
{
switch(i%2)
{
case 0:i--;break;
case 1:i--;continue;
}
i--;
i--;
printf("%d", i);
}while(i>0);
}
1、一维数组
2、二维数组
3、字符串
特点:同一数组中的所有元素都属于同一种数据类型(int char float)数组元素用数组名和相应的下标来确定。
方法:一个数组元素其实就是一个变量,在数组中称为带下标的变量。
类型名 数组名[常量表达式];
如:
float s[25];
float s[5*5];
int a[10];
char s1[30];
定义数组有四个注意:
数组名[下标]
先定义数组后使用
不能整体用数组名
注:C语言中不能对数组进行整体引用,只能单独引用其中的元素。引用时下标可以是如下形式。
char a[10];
a[0] = 'A';
a[3+7] = 'b';//错误
记住:数组元素下标的值在0和size-1之间。即下标范围属于[0, size-1]
格式:
类型名 数组名[常量表达式]={初值1, 初值2, ……};
注意:
类型名 数组名[常量表达式1][常量表达式2]
如:
int a[10][10];
char b[3][4];
float s[7][3];
注:
数组名要遵守用户自定义标识符的命名规则。
定义二维数组第一个方括号常量表示行数,第二个方括号常量表示列数。
int a[4*5]; //一维 20个元素个数
int a[4][5];//二维 4行5列 20个元素
定义数组时方括号中的表达式不能有变量,且表达式的值必须是大于 0 的正整数。
数组名[行下标][列下标];
注:
方法1:将初值依序放在一对 {} 中,与一维数组初始化格式相同。
例如:int a[2][3] = {1,2,3,4,5,6};
方法二:定义二维数组的同时,按行初始化每一行初值均用一对 {} 括起,采用嵌套的 {} 格式。
例如:int a[2][3]={ {1,2,3}, {4,5,6} };
注意:定义二维数组的同时给数组初始化,则可以省略行数,但列数不能省略。
例如:
int a[][3]= {1,2,3,4,5,6};//对?
int a[2][]= {1,2,3,4,5,6};//错?
int a[][3];//?
char s[]={‘a’, ‘b’, ‘c’, ‘d’, ‘e’};
与其它类型数组的初始化方式一样,只是其初始值是字符。
因为字符串最后都有一个字符串结束符(‘\0’),所以用字符数组来存放字符串时一定要有一个元素存放结束符’\0’
方法1:利用scanf();键盘输入
char a[10];
scanf(“%s”, a);//输入:ab cd<回车>
scanf(“%s”, &a); //非法
printf(“%s”, a);//输出时,从当前地址开始输出,遇到’\0’结束
注:用 %s 格式输入时,遇到空格符或回车符则自动结束输入。 scanf(“%s,%s”, a,b); 不能正确读取数据。
方法2:利用gets();键盘输入
功能:读取字符串赋值给字符数组。可有空格
注:
用gets()输入字符时,只有遇到回车才读取字符。
char str1[10];
gets(str1); //输入:ab cd<回车>
//str:ab cd
不论用%s还是gets()在输入时均不需要输入双引号。若输入了双引号则双引号也作为字符串的有效字符。
puts()输出
功能:屏幕上输出字符数组中的字符。
注:用该函数输出与用%s格式输出一样,只是该函数将’\0’转成’\n’输出。
//如;
puts("abc");put("def");
/* 输出结果:
abc
def
*/
方法3:利用字符数组初始化
char s[] = "abc";
char s[] = {"abc"};
char s[] = {'a', 'b', 'c', '\0'};
方法4:strcpy()
char a[10];
strcpy(a, "abcd");
方法4:字符串常量赋值给指针
char *s = "hello";
char *buf = "hello world";
第 1 函数:strcat()
格式:
#include
strcat(字符数组1, 字符数组2);
功能:“连接”
如:
char a[18] = "jack";
char b[10] = "zhy";
strcat(a,b);
/*
a=>"jackzhy"
b=>"zhy"
*/
第 2 个函数:strcpy():
格式:
#include
strcpy(字符数组1, 字符数组2);
功能:将字符数组2中的字符串替换到字符数组1中。函数值为字符串数组1的首地址。
如:
char str1[10] = "123456";
char str2[10] = "abc";
strcpy(str, str2);
// str1=> "abc"
// str2=> "abc"
第 3 个函数:strcmp()
#include
strcmp(字符数组1, 字符数组2);
功能:函数返回值相同位置不同字符的ASCII码差值。
返回值:一个整型数,是一个插值。
// strcmp("abc", "abc") => 0
// strcmp("abc", "abfc") => 'c' - 'f' => -3
// strcmp("abc", "ab") => 'c' - '\0' => 99
注:不能用关系运算符直接进行字符串大小或字符数组大小的比较。
//这是不行的
"abc" == "abc";
"abc" > "ab";
第4个函数:strlen()
格式:
#include
strlen(字符数组);
功能:求出字符数组的实际长度(不包括结束符)
char a[10] = "4332567";
printf("%d", strlen(a));//7
char a[10] = "abc\018\0"; // \01是8进制
printf("%d", strlen(a));//5
char a[10] = "abc\012\0"; // \012是8进制
printf("%d", strlen(a));//4
C语言程序的框架有两种:
注:
1、函数定义
函数返回值类型 函数名(形式参数列表)
{
函数体;
}
说明:
函数体可以没有语句,但不能没有花括号,函数名后必须有一对小括号。
定义有参函数时,形参的定义可以采用传统方式或现代方式两种。
//传统方式:
int max(x,y)
int x,y; // 不能定义形参以外的其它变量
{
//...
}
//现代方式:
int max(int x, int y)
{
}
函数返回值类型:两类
// 形式1:非void型(int float double等...)
int fun(int x, int y)
{
return 表达式;
}
// 形式2:void型
void fun(int x, int y)
{
//不加return
}
方式一:非void型
变量名 = 函数名(实参列表);
方式二:void型
函数名(实参列表);
(1)原型声明
方式一:#include<头文件> (库函数)
方式二:声明的格式 (用户自定义函数)
函数类型 函数名(形参类型1 形参1, 形参类型2 形参2, …);
函数类型 函数名(形参类型1, 形参类型2, …);
void sum(int x, int y); /*函数原型声明*/
int main()
{
sum(3, 5);
return 0;
}
void sum(int x, int y)
{
printf("%d", x+y);
}
函数定义:
函数返回值类型 函数名(形式参数列表)
{
函数体;
}
//这是函数的定义
函数声明:
函数类型 函数名(形参类型1 形参1, 形参类型2 形参2, ...);
函数类型 函数名(形参类型1, 形参类型2, ...);
//这是函数的声明语句
void sum(int x, int y);
int main()
{
sum(3, 5);
return 0;
}
void sum(int x, int y)
{
printf("%d", x+y);
}
变量三属性:
就是数据类型,如int、float、double
(1)局部变量(内部变量)
定义:在一个函数内部定义的变量称为局部变量
(2)全局变量(外部变量)
定义:在函数外部定义的变量为全局变量
全局变量也是静态变量
(1)auto变量(默认)
(2)static变量
(3)register类别变量
(4)extern类别变量
文件包含(include)
#include <>
#inclulde “”
格式:
#define 宏名 宏内容
功能:用一个指定的标识符(宏名)来代表一串字符串(宏内容)。
如:
#define PI 3.141592
#define N 10
注:
#define 宏名(参数列表) 宏内容
功能:提供了一种更加灵活的替换方式。
如:#define s(x,y) x*y+2
注:
C语言有两种变量:其中变量(普通变量)存储内容值;地址变量(指针变量)存储地址值。
类型名 *指针变量名;
如:
int a, b, *p1, *p2;
float x, y, *p3, *p4;
char s, *p5, *p6;
int b, *a;
int* a;
注:
“&”取地址运算符,通过&运算符可以取出普通变量的地址。
指针运算符,*可以取出指针变量所指向的普通变量的值,(间接引用普通量)。
*指针变量名
如:
int a,b=20,c=30,d=40,*p;
p = &d;
a = *p; //a=d;
说明:int fun(int a[10]) <=> int fun(int *a) <=> int fun(int a[])
若数组做为形参,则将数组名做指针变量来处理。
由于数组元素与普通一样,所以定义指向数组元素的指针变量与定义指向普通变量的指针变量完全一样
注:
(1)C语言中规定:数组名代表数组的首地址,而且是一个地址常量
(2)当指针变量指向数组中的某一个元素时,指针变量加1后指向数组中后一个元素,指针变量减1时指向数组中前一个元素。
(3)若两个指针变量指向同一个数组,则这两个指针变量可以进行大小比较如:
char s[10];
char *p1 = s+3, *p2 = &s[7];
//则 p1 > p2 ===> 0 p1 < p2 ===> 1
// p1 - p2 == -4
(4)在形参中的数组实际上是一个指针变量,并不是真正的数组,因为该“数组名”的值是可以改变的,而真正的数组名的值是不能改变的。
(5)若形参是数组或指针变量,则在函数中可以通过该形参改变实参的值。
若a是一个二维数组,则:
//若有以下定义:
int w[2][3];
//则对w数组元素的非法引用是:
/*
A:*(w[0]+2)
B:*(w+1)[2]
C:w[0][0]
D:*(w[1]+2)
E:w[1]+2
*/
如:
int a[3][4];
int *p = &a[0][3];
//则:
p+1指向元素a[1][0];
p+4指向元素a[1][3];
p-2指向元素a[0][1];
常用于取二维数组a元素地址的方式:&a[i][j]、a[i][j]、*(a+i)+j 元素地址
定义指向由m个元素组成的一维数组的指针变量的格式:
基类型 (*指针变量名)[m];
如:
int a[5][7];//a是行地址
int (*p)[7];
p=a;
char b[10][80];
char(*r)[80];
r = b+5;
符串常量:C语言对字符串常量是按首地址处理字符串常量的
函数名与数组名一样,是起始地址,而且是一个地址常量
定义指向函数的指针变量的方式:
类型名 (*指针变量名)();
有()的标志说明是函数
一维数组 列地址
二维数组 行地址
函数 函数地址
区分:
/*
类型名 (*指针变量名)();
类型名 普通变量名:
类型名 数组名[];
类型名 *指针变量名:
类型名 函数名()
{....}
类型名 (*指针变量名)[M];
*/
注:
(1)在定义指向函数的指针变量时,要注意有两个小括号必须要有,不需要定义形参。
(2)单独的函数名代表该函数的首地址(函数的入口地址)
(3)函数的指针变量只能指向函数的入口处(函数的首地址),不能指向函数中的某条指令。(
另外,对指向函数的指针变量加1是没有意义的)。
(4)给指向函数的指针变量赋值时,只写函数名即可,不必写参数。
类型名 函数名(形参)
{
}
返回指针的函数的定义方式为:
类型名 *函数名(形参)
{
return 地址值;
}
格式:
类型名 *数组名[常量表达式];
int *s[10];
注:
(1)要注意它与定义指向m个元素组成的一维数组的指针变量之间的区别
类型名 *数组名[常量表达式];
类型名 (*指针名)[常量表达式m];
(2)它的每个元素都是一个指针类型(地址),即它的每个元素相当于一个指针变量。
int *a[10]:
int a[10]:
int a[10][10]:
2、指向指针的指针变量
用来存放指针变量地址的指针变量 称为 指向指针的指针变量。
定义格式:基类型名 **指针变量名;
如:
int a=3;
int *p = &a;
int **k = &p;
/*
则:*k得到变量p(变量a的地址)
*/
指针变量可以有空值,即指针变量不指向任何变量,不指向任何有用的存储单元。
在系统中已将NULL定义为0,即NULL的值为0。
int a,b,c,*p=NULL;
此时p的值为空指针,即p不指向任何有用的存储单元。尽管NULL的值为0,但我们不能认为p指向了地址为0的存储单元。
注:
(1)当一个指针变量的值为空指针时,我们不能引用它所指向的存储单元。
(2)若某指针(地址)的基类型为void型,则有引用时应进行相应的强制类型转换。
#include
main()
{
int a[]={1,2,3,4,5,6,7,8,9,10,11,12};
int *p=a+5,*q=NULL;
*q=*(p+5)
printf("%d %d\n",*p,*q);
}
输出:
struct 结构体类型名
{
成员1的定义;
成员2的定义;
......;
成员n的定义;
};
struct student
{
int sn;
int age;
char sex;
int s[3];
};
注:
(1)定义成员的方式与定义普通变量的方式一样
(2)成员列表必须用一对花括号括起
(3)结构体名可以省略。
A.先定义结构体类型名再定义结构体变量
main()
{
struct student
{
int sn;
int age;
char sex;
int s[3];
}; /*类型定义*/
struct student stu1,stu2,st[25];/*变量定义*/
}
B.在定义结构体类型同时定义变量
struct student
{
int sn;
int age;
char sex;
int s[3];
}stu1,stu2,st[25];
C.类型、变量同时定义,类型名student省略
struct
{
int sn;
int age,
char sex;
int s[3];
}stu1,stu2,st[25];
注:
(1)结构体变量在内存中占用字节数为各成员占用字节数总和。【有待商榷】
(1)再定义结构体变量的同时可以将各成员的初值按顺序放在一对花括号中,来进行对结构体变量的初始化。若初值个数多于成员个数则出错,若初值个数少于成员个数,则多余成员自动赋0。
struct aa
{
int a;
char b[10];
float c;
} a1={30, "china", 40.5}, a2={60,"hello"};
(2)结构体变量不能整体引用,只能引用它的成员(同数组相似)
/* 引用结构体成员的方式:
结构体变量名.成员名
其中.为成员运算符
*/
printf("al=%d,%s,%f", a1);//非法/
printf("al=%d,%s,%f", a1.a, a1.b, a1.c);
a1.a=80;
a1.b="xinjiang";//strcpy(a1.b, "abc")
a1.c=60.5;
struct student
{
int num;
char name[20];
char sex;
float score;
};
struct student stu[3] = {{1001,"zhang",'M',60.5},
{1002,"li",'M',100},
{1003,"wang",'W',90.9}};
struct student *p=stu;// &stu[0]等价
//引用成员:
stu[1].num;(p+1)->num;(*(p+1)).num;
stu[0].name;p->name;(*p).name;
注:
(1)可以用结构体变量的成员作为实参,它与普通变量作为实参的用法是一样的。
(2)用结构体变量作为实参时,要求形参必须是同一结构体类型的变量,传递后形参与实参各对应成员值是一样的。
(3)也可以用结构体类型的地址(指针变量或数组)作为实参,要求形参必须是同一结构体类型的指针变量或数组。只要是地址传递,则间可以通过形参来改变实参的值。
共用体中的所有成员共用同一段内存(所有成员的起始地址都是一样的)
格式:
union 共用体名
{
成员列表;
};
注:
(1)成员列表为定义该共用体的成员,成员定义的方式与普通变量的方式一样。
(2)成员列表必须用一对花括号括起。
(3)共用体名可以省略。
(1)先定义类型,再定义变量
(2)定义类型的同时,定义变量
(3)直接定义变量
union data
{
int i;
char ch[10];
float s;
}
注:
由于共用体类型变量的所有成员公用同一段内存,所以共用体类型变量所占的字节数等于该共用体类型中占字节数最多的成员所占的字节数。
注:
(1)不能整体引用共用体变量,只能引用其成员。
(2)同类型成员共享值。
(3)在内存中整型数据的二进制数低8位占用前面一个字节,高8位占用后面一个字节。
如:
整数255,在内存中的存储形式是:
1111 1111 0000 0000
一个字符型数据占用一个字节,对于数组来说前面元素占用前面的字节。
(4)共用体变量之间可以相互赋值,赋值后两个变量应使用同一成员。
(5)共用体变量的地址与各成员的地址都相同的。
(6)在定义共用体时,可以对其进行初始化,但只能有一个初值且必须用花括号将初值括起。相当于给第一个成员赋值。
(7)共用体、结构体的成员均可以是共用体或结构体类型
(8)不能用共用体类型变量做为函数参数。
(9)计算共用体占用字节数。
用typedef 定义新类型名
在编程中可以用typedef来定义新的类型名来代替已有的类型名。给已有类型起别名。
格式:
typedef 已有类型名 新的类型名;
如:
typedef int INTEGER;
//以后在定义变量时int和INTEGER是等价的。
INTEGER a[10],b; int a[10],b;
(1)typedef可用于定义各种类型名,但不能定义变量,即只要见到typedef则该语句最后的标识符必定是一个类型名而不是变量名。
(2)typedef只能对已经存在的类型新增一个别名,而不是创造新类型。即在ypedef后必须是一个已有的类型。
位运算的操作对象只能是整型或字符型数据。
C语言提供6种位运算符:
& | ^ ~ << >>
复合赋值运算符:
&= |= ^= <<= >>=
两个相应的二进制位都是1时,它们按位运算后的结果才是1,否则为0。
1&1=1
1&0=0
0&1=0
0&0=0
全1为1;有0为0。
作用:清零。
两个相应的二进制位中只要有一个为1,则它们按位或运算后结果为1。
1|1=1
1|0=1
0|1=1
0|0=0
作用:将特定位 置1。
当两个相应的位同为1或同为0时,按位异或运算结果为0;两个相应位一个为1另一个为0时,按位异或运算结果为1。
1^1=0
1^0=1
0^1=1
0^0=0
相同为0,相异为1
按位取反运算符是一个单目运算符。按位取反后0变1,1变0。
注:
对一个数按位取反得到的值为该数+1后再乘-1。???
格式:数<
对一个十进制数左移n位后得到的值为该数乘以2n的积。
格式:数>>n
功能:将二进制位按位依序右移n位。
若该数为一个负数并且不能被2n整除则得到的数为商加-1。
1、文件的打开(fopen()函数)
格式:fopen(文件名,文件使用方式)
功能:按指定的“使用方式”打开文件,函数返回打开文件的指针,该指针的基类型为文件类型。文件名和文件使用方式均为字符串。
如:以只读方式打开文件data.txt,并用指针变量fp指向它。
FILE *fp;
fp = fopen("data.txt", "r");
打开文件的“使用方式”:
“r”:打开已存在的文件
“w”:刷新写、创建写
“a”:追加写、创建写
“+”:增强
“r+” “w+” “a+”
“rb” “wb” “ab”
“rb+” “wb+” “ab+”
注:
(1)文件使用方式只能用小写字母,文件名用大写或小写均一样。
如:
FILE *fp;
fp = fopen("c:\\tc\\data.txt", "w");
(2)在“文件使用方式”中若含有字母 b,则打开的是一个二进制文件(bit)。
(3)当fopen“打开”失败时,函数返回NULL。
if (fp = fopen(文件名, 文件使用方式)==NULL)
{
printf("can not open this file\n");
exit(0);
}
2、文件的关闭(fclose函数)
文件使用完后应该关闭该文件。
格式:fclose(文件指针);
如:fclose(fp);
(1)fputc()
格式:fputc()
功能:把一个字符写到文件指针所指的文件中。其中字符可以是字符常量也可以是字符变量。若输出成功则函数返回输出的字符,失败则返回EOF(stdio.h中定义为-1)。
(2)fgetc()
格式:fgetc(文件指针)
功能:从文件指针所指文件中读取一个字符。若读取成功则函数返回读取的字符,失败(遇到文件结束)则返回EOF。
char ch;
ch = fgetc(fp);
(3)fgets()
格式:fgets(str, n, fp)
功能:其中str表示一个字符指针,可以是字符数组名也可以是字符指针变量名。从fp所指文件中读取n-1个字符(不是n个字符),并在这些字符最后加一个字符串结束符’\0’后赋给str。
函数返回str的首地址。
(4)fputs()
格式:fputs(str, fp)
功能:向fp所指文件中写(输出)str中的字符串,str可以是字符串常量、字符数组或字符指针变量。在输出时字符串的结束符’\0’不会输出。若输出成功则返回0,失败返回EOF(stdio.h中定义为-1)。
(5)fread()、fwrite()
格式:
fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);
其中:
buffer时数据的地址
size是每次读写的字节数
count表示让函数进行多少次的读写
fp是要进行读写的文件指针变量
功能:用来读写一个连续的数据块
注:
(6)fprintf()、fscanf()
格式:
fprintf(文件指针, 格式说明符, 输出列表);
fscanf(文件指针, 格式说明符, 输入列表);
功能:按格式说明符所指定的格式向文件中读写(输入输出)数据。其中格式说明符和输入(输出)列表的用法与scanf和printf函数相同。
补充:feof(文件指针)
作用是测试文件的当前读写位置是否到达文件末尾,若是则返回非0值(真),否则返回0(假)。
while(!feof(fp))
{
}
(1)重新定位指针
格式:rewind(文件指针)
作用:使当前的读写位置重新指向文件的开头。函数无返回值。
(2)fseek()
格式:fseek(文件指针,位移量,起始点)
功能:将当前的读写位置从“起始点”开始按“位置量”所指定的移动字节数向后移动。
起始点有:
SEEK_SET 或 0 (表示“文件的开始”)
SEEK_CUR 或 1 (表示“当前位置”)
SEEK_END 或 2 (表示文件末尾)
位移量:要在数值后加字母l或L。
如:
fseek(fp, 100L, SEEK_SET)
(3)ftell()
格式:ftell(文件指针)
功能:返回当前文件的位置值,用相对于文件头的位移量表示。若返回-1L表示出错。