1.变量(按空间分类)
(1)局部变量
在函数内部定义的变量只在函数内部有效,包括main()函数;在复合语句定义的变量只在本复合语句有效。以上这些变量称为局部变量。
(2)全局变量
在函数外部定义的变量称为全局变量,可以被本文件中其他函数所共用,有效范围从定义变量的位置开始到本源文件结束。
如果全局变量与局部变量同名,那么在局部变量有效的范围内,全局变量被屏蔽,只有局部变量才有效。
2.变量(按时间分类)
变量的存储分为静态存储和动态存储。静态存储是由程序运行期间由系统分配固定的存储空间;动态存储是根据需要动态分配存储空间。
静态存储主要有全局变量;动态存储有:函数形式参数,在调用函数时给形参分配存储空间;自动变量,即函数中定义的没有用static修饰的局部变量。
(1)自动(auto)局部变量
函数中定义的局部变量,如果啥都不写,则默认自动变量,我们绝大多数定义的都是自动变量。
(2)静态(static)局部变量
如果希望函数中的局部变量的值在函数调用结束后不消失而继续保持原值,即其所占用的存储单元不释放,可用static修饰,定义为静态局部变量,使其采用静态存储方式。
静态局部变量是在编译的时候赋初值的,且只赋初值一次,在程序运行时它已有初值。而对自动变量赋初值,不是在编译时进行,而是在函数调用时进行。静态局部变量在函数调用结束后依然存在,但因为还是局部变量,所以只能被自己函数调用。
(3)全局变量
1.在一个文件内扩展外部变量的作用域
全局变量只在定义处之后才有效。如果想在定义点之前引用全局变量,可用extern作全局变量声明,把全局变量的作用域扩大到此范围。
例7.18:调用函数,求三个整数中的大者
#include<stdio.h>
int main()
{
int max();
extern int A,B,C;//把外部变量A,B,C的作用域扩展到此处开始
printf("please enter three integer numbers:\n");
scanf("%d %d %d",&A,&B,&C);
printf("max is %d\n",max());
}
int A,B,C; //定义外部变量A,B,C
int max()
{
int m;
m=A>B?A:B;
if(C>m)
m=C;
return (m);
}
2.将外部变量的作用域扩展到其他文件
如果一个程序包含两个文件,在两个文件中都要用到同一个外部(全局)变量Num,不能两个文件分别定义,而应在一个文件中定义外部变量Num,而在另一个文件中用extern Num对Num做外部变量声明。
//文件file.1
#include<stdio.h>
int A; //定义外部变量
int main()
{
int power(int t);
int b=3,c,d,m;
printf("enter the number a and its power m:\n");
scanf("%d %d",&A,&m);
c=A*b;
printf("%d*%d=%d\n",A,b,c);
d=power(m);
printf("%d**%d=%d\n",A,m,d);
}
//文件file.2
extern A; //把在file1文件中定义的外部变量的作用域扩展到本文件
int power(int n)
{
int i,y=1;
for(i=1;i<=n;i++)
y*=A;
return (y);
}
3.将外部变量的作用域限制在本文件中
如果希望外部变量只限于被本文件引用,而不能被其他文件引用,可在定义外部变量时加一个static,称为静态外部变量。
声明和定义
一般,需要建立存储空间的为声明,不需要建立存储空间的为定义。
有一个简单结论,在函数中出现的对变量的声明(除了extern声明)都是定义。在函数中对函数的声明不是定义。
3.函数
如果不加声明的话,默认一个文件中的函数既可以被本文件中的其他函数调用,也可以被其他文件中的函数调用。但是,也可以指定函数不能被其他文件调用。前者称为外部函数,后者称为内部函数。
(1)内部函数
又称为静态函数,只能被本文件中的其他函数调用。这样,即使不同的文件中有同名的内部函数,也互不干扰。
格式:
static 类型名 函数名(形参表)
如:
static int fun(int a,int b)
(2)外部函数
加关键字extern,如果不加则默认是外部函数。可供其他文件调用。
格式:
extern int fun(int a,int b)
同时,在需要调用此函数的其他文件中,需要对此函数作声明(即使在本文件中调用一个函数,也要用函数原型进行声明)。在对函数进行声明时,加extern,表示该函数是在其他文件中定义的外部函数。声明时extern可以省略,只写函数原型。
例7.20
//file1.c 文件1
#include<stdio.h>
int main()
{
extern void enter_string(char str[]);
extern void delete_string(char str[],char ch);
extern void print_string(char str[]);
//声明在本函数中所要调用的其他文件中定义的函数,extern可以省略
char c,str[80];
enter_string(str);
scanf("%c",&c);
delete_string(str,c);
print_string(str);
}
//file2.c 文件2
void enter_string(char str[80])
{
gets(str);
}
//file3.c 文件3
void delete_string(char str[],char ch)
{
int i,j;
for(i=j=0;str[i]!='\0';i++,j++)
if(str[i]!=ch)
str[j]=str[i];
str[j]='\0';
}
//file4.c 文件4
void print_string(char str[])
{
printf("%s\n",str);
}
结构体
例:
struct Student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}; //注意有分号
例:成员可以是另一个结构体类型
struct Date
{
int month;
int day;
int year;
};
struct Student
{
int num;
char name[20];
char sex;
int age;
struct Date birthday;
char addr[30];
};
使用结构体类型定义变量:
1.先声明结构体类型,再定义
struct Student student1,student2;
2.再声明类型的同时定义
struct Student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}student1,student2;
结构体的初始化和引用
例:
#include<stdio.h>
int main()
{
struct Student
{
long int num;
char name[20];
char sex;
char addr[20];
}a={10101,"lyl",'m',"road"};
printf("NO.:%d\nname:%s\nsex:%c\naddres:%s\n",a.num,a.name,a.sex,a.addr);
}
#include<stdio.h>
int main()
{
struct Student
{
int num;
char name[20];
float score;
}student1,student2;
scanf("%d %s %f",&student1.num,student1.name,&student1.score);
//注意输入格式
scanf("%d %s %f",&student2.num,student2.name,&student2.score);
printf("The higher score is:\n");
if(student1.score>student2.score)
printf("%d %s %6.2f\n",student1.num,student1.name,student1.score);
else
printf("%d %s %6.2f\n",student2.num,student2.name,student2.score);
}
使用结构体数组
#include<stdio.h>
#include<string.h>
struct Person
{
char name[20];
int count;
} leader[3]={{"lyl",0},{"lyl1",0},{"lyl2",0}};
int main()
{
int i,j;
char leader_name[20];
for(i=1;i<=10;i++)
{
scanf("%s",leader_name);
for(j=0;j<3;j++)
if(strcmp(leader_name,leader[j].name)==0)
leader[j].count++;
}
printf("\nResult\n");
for(i=0;i<3;i++)
printf("%5s:%d\n",leader[i].name,leader[i].count);
}
#include<stdio.h>
struct Student
{
int num;
char name[20];
float score;
};
int main()
{
struct Student stu[3]=
{{10101,"lyl1",60},{10102,"lyl2",61},{10103,"lyl3",62}};
struct Student temp;
const int n=3;
int i,j,k;
printf("The order is:\n");
for(i=0;i<n-1;i++)
{
k=i;
for(j=i+1;j<n;j++)
if(stu[j].score>stu[k].score)
k=j;
temp=stu[k];
stu[k]=stu[i];
stu[i]=temp;
}
for(i=0;i<n;i++)
{
printf("%6d %8s %6.2f\n",stu[i].num,stu[i].name,stu[i].score);
printf("\n");
}
}
结构体指针
例:
#include<stdio.h>
#include<string.h>
int main()
{
struct Student
{
long num;
char name[20];
char sex;
float score;
};
struct Student stu_1;
struct Student *p;
p=&stu_1;
stu_1.num=10101;
strcpy(stu_1.name,"lyl");
stu_1.sex='m';
stu_1.score=89.5;
printf("No:%ld\nname:%s\nsex:%c\nscore:%5.1f\n",stu_1.num,stu_1.name,stu_1.sex,stu_1.score);
printf("No:%ld\nname:%s\nsex:%c\nscore:%5.1f\n",p->num,p->name,p->sex,p->score);
}
结构体数组指针
#include<stdio.h>
struct Student
{
int num;
char name[20];
char sex;
int age;
};
struct Student stu[3]=
{{1,"lyl1",'m',10},{2,"lyl2",'m',11},{3,"lyl3",'m',12}};
int main()
{
struct Student *p;
printf("No. name sex age\n");
for(p=stu;p<stu+3;p++)
printf("%5d %-5s %2c %4d\n",p->num,p->name,p->sex,p->age);
}
用结构体变量和结构体的指针作为函数参数
#include<stdio.h>
#define N 3
struct Student
{
int num;
char name[20];
float score[3];
float aver;
} ;
int main()
{
void input(struct Student *stu); //注释1
struct Student max(struct Student *stu);
void print(struct Student stu); //注释2
struct Student stu[N],*p=stu;
input(p); //注释3
print(max(p));
}
void input(struct Student stu[])
{
int i;
printf("please enter the information:\n");
for(i=0;i<N;i++)
{
scanf("%d %s %f %f %f",&stu[i].num,stu[i].name,
&stu[i].score[0],&stu[i].score[1],&stu[i].score[2]);
stu[i].aver=(stu[i].score[0]+stu[i].score[1]+stu[i].score[2])/3.0;
}
}
struct Student max(struct Student stu[])
{
int i,m=0;
for(i=0;i<N;i++)
if(stu[i].aver>stu[m].aver)
m=i;
return stu[m];
}
void print(struct Student stud)
{
printf("\n成绩最高的学生是\n");
printf("%d\n%s\n%5.1f %5.1f %5.1f %6.2f",
stud.num,stud.name,stud.score[0],stud.score[1],stud.score[2],stud.aver);
}
注释1:
*stu也可以换成stu[],但前者更加专业,这里表示形参是指向struct Student类型的指针,即地址,后面传入的p所装载的就是地址。 见注释3.
注释2:
形参不是地址,而是struct Student类型的数据。
链表
前面提到,全局变量分配在静态存储区;非静态局部变量存储在动态存储区,称为栈;另外,用户可以根据需要建立堆区,根据需要随时开辟,不需要时随时释放,但只能通过指针来引用。
int a=3;
int *p1=&a;
char *p;
void *p3;
p3=(void*)p1; //@1
p2=(char*)p3;
printf("%d",*p1);
p3=&a;printf("%d",*p3); //@2
@1:
(void*)可以省略,系统会进行自动强制类型转换。
@2:
错误用法,void类型的指针是不指向任何具体类型的指针。
#include<stdio.h>
#include<stdlib.h>
int main()
{
void check(int *);
int *p1,i;
p1=(int *)malloc(5*sizeof(int));//可以省略(int*)
for(i=0;i<5;i++)
scanf("%d",p1+i);
check(p1);
}
void check(int *p)
{
int i;
printf("They are fail:");
for(i=0;i<5;i++)
if(p[i]<60)
printf("%d ",p[i]);
printf("\n");
}
链表
结构体非常适合用来建立链表,结构体的成员可包含指针类型,用来存放下一个结点的地址,如:
struct Student
{int num;
float score;
struct Student *next;
};
静态链表:
#include<stdio.h>
struct Student
{
int num;
float score;
struct Student *next;
};
int main()
{
struct Student a,b,c,*head,*p;
a.num=1;a.score=10;
b.num=2;b.score=20;
c.num=3;c.score=30;
head=&a;
a.next=&b;
b.next=&c;
c.next=NULL;
p=head;
do
{
printf("%ld %5.1f\n",p->num,p->score);
p=p->next;
}while(p!=NULL);
}
重点!!!
动态链表
在原基础上增加一个输出的函数print:
#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct Student)
struct Student
{
long num;
float score;
struct Student *next;
} ;
int n;
struct Student *creat()
{
struct Student *head;
struct Student *p1,*p2;
n=0;
p1=p2=(struct Student*)malloc(LEN);
scanf("%ld %f",&p1->num,&p1->score);
head=NULL;
while(p1->num!=0)
{
n=n+1;
if(n==1) head=p1;
else p2->next=p1;
p2=p1;
p1=(struct Student*)malloc(LEN);
scanf("%ld %f",&p1->num,&p1->score);
}
p2->next=NULL;
return(head);
}
void print(struct Student*head)
{
struct Student *p;
printf("\nThese %d records are:\n",n);
p=head;
if(head!=NULL)
do{
printf("%ld %5.1f\n",p->num,p->score);
p=p->next;
}while(p!=NULL);
}
int main()
{
struct Student *head;
head=creat();
经试验,发现Dev不支持void类型指针的强制类型转换,需要手动进行转换。
如果在main()之后定义a函数,而在main()中需要调用函数,那么就需要在main()中进行函数原型的声明,当然,也可以在main()外部进行声明,只要在调用a函数之前就行。如果在main()函数之前就定义了,那么不需要声明。因为系统编译是按顺序由上到下进行编译的。
共用体类型
共用体又名联合,几个变量共用同一个内存区。
例:
#include<stdio.h>
struct
{
int num;
char name[10];
char sex;
char job;
union
{
int clas;
char position[10];
}category;
} person[2];
int main()
{
int i;
for(i=0;i<2;i++)
{
printf("please enter the data\n");
scanf("%d %s %c %c",
&person[i].num,&person[i].name,&person[i].sex,&person[i].job);
if(person[i].job=='s')
scanf("%d",&person[i].category.clas);
else if(person[i].job=='t')
scanf("%s",person[i].category.position);
}
for(i=0;i<2;i++)
{
if(person[i].job=='s')
printf("%6d %10s %4c %4c %10d\n",
person[i].num,person[i].name,person[i].sex,person[i].job,person[i].category.clas);
else
printf("%6d %10s %4c %4c %10s\n",
person[i].num,person[i].name,person[i].sex,person[i].job,person[i].category.position);
}
}
枚举类型
对于枚举类型的花括号里的枚举元素,虽然可以给它们一个名称,但其本质上还是整数,系统编译时也还是按照整数进行处理的。
错误:
#include<stdio.h>
int main()
{
enum Weekday{sun,mon,tue,wed,thu,fri,sat};
int sun=10;
enum Weekday workday=sun;
printf("%d\n",sun);
printf("%d",workday);
}
edeclared as different kind of symbol 系统显示重复定义。
正确:
#include<stdio.h>
int main()
{
enum Weekday{sun,mon,tue,wed,thu,fri,sat};
enum Weekday workday=sun;
printf("%d\n",sun);
printf("%d",workday);
}
输出值都为0