一、结构体
1、概念:
结构体是复合的数据类型,是不同类型 数据的集合
在C语言中没有具体的结构体类型,但是C语言给出了定义结构体类型的语法格式,所以结构体也成为自定义类型
2、结构体类型定义的语法格式
struct <结构体标签>{
成员类型 成员名;
成员类型 成员名;
.... ....
成员类型 成员名;
};
例如:定义一个学生的类型
struct student{
int sno;
char name[20];
int age;
float score;
};
3、结构体变量的定义
1》常规定义:
struct student{
int sno;
char name[20];
int age;
float score;
};
struct student st1; //st1为结构体变量
2》与类型同时定义
struct student{
int sno;
char name[20];
int age;
float score;
}st2; /st2为结构体变量
3》直接定义
struct {
int sno;
char name[20];
int age;
float score;
}st3; /st3为结构体变量
4、结构体变量的初始化
1》完全初始化
不按顺序给结构体中某一些成员赋值,例如:
1》赋值:
除了初始化之外,不能像 .name="张飞",25,.sno = 1002 这样赋值,例如
struct student st;
st = {100,"abc",22,95.7}; //错误
但是:同类型的结构体变量之间可以相互赋值,例如:
struct student st;
//st = {1001,"张飞",25,98.1}; //错误的
st = st1; //正确的
另外,也可以分别给每一个成员赋值,例如:
st.sno = 1001;
strcpy(st.name,"赵云");
st.age = 26;
st.score = 95.7;
元素为结构体类型的数组称为结构体数组,例如:
指向结构体变量的指针称为结构体指针,例如:
1》基本类型:
struct A{
int a;
float b;
};
2》数组:
struct A{
int a[5];
float b;
};
3》结构体:
例1:
也叫联合体,是一种复合数据类型,C语言中也没有该类型的具体定义,但是给出了定义该类型的语法格式
也是由不同类型数据组成,但是共用体中的多个数据共同使用同一块内存空间。
1、共用体类型的定义
union <共用体标签>{
成员类型 成员名;
成员类型 成员名;
.... ....
成员类型 成员名;
};
例如:定义一个共用体的类型
union student{
int sno;
char name[20];
int age;
float score;
};
2、共用体变量的定义
1》常规定义:
union student{
int sno;
char name[20];
int age;
float score;
};
union student st1; //st1为共用体变量
2》与类型同时定义
union student{
int sno;
char name[20];
int age;
float score;
}st2; /st2为共用体变量
3》直接定义
union {
int sno;
char name[20];
int age;
float score;
}st3; /st3为共用体变量
3、使用
1》赋值和打印与结构体类似,例如:
1》共用体的成员共同使用同一块内存空间
2》在程序中,某一时刻只有一个成员的值有效,即最后被赋值的成员有效
实例:
判断机器的字节序?
该类型的本质是整型,为了提高程序额可读性,同时为了人为的程序中的一些数据规定一个取值的范围,而设计出这样的枚举类型,例如
在程序中表示一周的每一天,或者一年中的每个月都可以定义成枚举类型
1、枚举类型的定义
enum <枚举标签>{
枚举常量,
枚举常量,
.....
枚举常量
};
例如:
enum phone_color{
white, //枚举常量
black, //枚举常量
golden //枚举常量
};
默认情况下,枚举常量的值,从第一个开始依次是:0,1,2,3,....
enum phone_color color; //color为枚举变量,一般在程序中取枚举常量的值
1、自然对齐
在数据分配空间时,如果该数据的起始地址能够被它的长度整除,则就是自然对齐
2、数据的M值
如果该数据的长度小于机器字长,则M值为该数据的长度
如果该数据的长度大于等于机器字长,则M值为机器字长。
3、适当对齐
在数据分配空间时,如果该数据的起始地址能够被它的M值整除,则就是适当对齐
4、不同类型数据的对齐
1》基本类型数据
按M值适当对齐
2》数组:
按元素的M值对齐
4》共用体:
按共用体变量的M值对齐,即:成员中M值最大的
5》结构体:
按结构体变量的M值对齐,即:成员中M值最大的
调用时,可以传不同类型的参数或者传不同个数的参数,这样的函数称为变参函数。
int printf(const char *format, ...);
指的是函数调用的一种方式,简单来说:间接调用的函数称为回调函数,例如:
1、概念:
结构体是复合的数据类型,是不同类型 数据的集合
在C语言中没有具体的结构体类型,但是C语言给出了定义结构体类型的语法格式,所以结构体也成为自定义类型
2、结构体类型定义的语法格式
struct <结构体标签>{
成员类型 成员名;
成员类型 成员名;
.... ....
成员类型 成员名;
};
例如:定义一个学生的类型
struct student{
int sno;
char name[20];
int age;
float score;
};
3、结构体变量的定义
1》常规定义:
struct student{
int sno;
char name[20];
int age;
float score;
};
struct student st1; //st1为结构体变量
2》与类型同时定义
struct student{
int sno;
char name[20];
int age;
float score;
}st2; /st2为结构体变量
3》直接定义
struct {
int sno;
char name[20];
int age;
float score;
}st3; /st3为结构体变量
4、结构体变量的初始化
1》完全初始化
按顺序给结构体中的每个成员赋值,例如
struct student st1 = {1001,"张飞",25,98.1};
2》部分初始化
按顺序给结构体中的前若干个成员赋值,例如:
struct student st2 = {1001,"张飞"}; //st2为结构体变量
3》指定成员初始化
不按顺序给结构体中某一些成员赋值,例如:
struct student st3 = {.name="张飞",25,.sno = 1002}; //st2为结构体变量
5、结构体变量的使用:
1》赋值:
除了初始化之外,不能像 .name="张飞",25,.sno = 1002 这样赋值,例如
struct student st;
st = {100,"abc",22,95.7}; //错误
但是:同类型的结构体变量之间可以相互赋值,例如:
struct student st;
//st = {1001,"张飞",25,98.1}; //错误的
st = st1; //正确的
另外,也可以分别给每一个成员赋值,例如:
st.sno = 1001;
strcpy(st.name,"赵云");
st.age = 26;
st.score = 95.7;
2》打印:
不能整体打印,必须分别打印每一个成员,例如:
printf("st1:%d,%s,%d,%f\n",st1.sno,st1.name,st1.age,st1.score);
printf("st2:%d,%s,%d,%f\n",st2.sno,st2.name,st2.age,st2.score);
printf("st3:%d,%s,%d,%f\n",st3.sno,st3.name,st3.age,st3.score);
printf("st:%d,%s,%d,%f\n",st.sno,st.name,st.age,st.score);
3》传参:
1)值传递
void fun1(struct student st)
{
printf("st:%d,%s,%d,%f\n",st.sno,st.name,st.age,st.score);
st.sno = 1001;
strcpy(st.name,"赵云");
st.age = 26;
st.score = 95.7;
}
2)地址传递
void fun2(struct student * pst)
{
printf("in_fun2:%d,%s,%d,%f\n",(*pst).sno,(*pst).name,(*pst).age,(*pst).score);
(*pst).sno = 1001;
strcpy((*pst).name,"赵云");
(*pst).age = 26;
(*pst).score = 95.7;
}
int main(void)
{
struct student st1 = {1001,"张飞",25,98.1}; //st2为结构体变量
#if 0
fun1(st1); //值传递
printf("st1:%d,%s,%d,%f\n",st1.sno,st1.name,st1.age,st1.score);
#else
fun2(&st1); //地址传递
printf("st1:%d,%s,%d,%f\n",st1.sno,st1.name,st1.age,st1.score);
#endif
return 0;
}
6、结构体数组
元素为结构体类型的数组称为结构体数组,例如:
#include <stdio.h>
#include <string.h>
//结构体类型定义
struct student{
int sno;
char name[20];
int age;
float score;
};
int main(void)
{
struct student st[50] = {{1001,"张三",25,99},{1002,"李四",22,95},{1003,"王五",26,97}};
int i;
for(i = 0; i < 3; i++)
printf("%d,%s,%d,%f\n",st[i].sno,st[i].name,st[i].age,st[i].score);
return 0;
}
7、结构体指针
指向结构体变量的指针称为结构体指针,例如:
#include <stdio.h>
//结构体类型定义
struct student{
int sno;
char name[20];
int age;
float score;
};
int main(void)
{
struct student st = {1001,"张三",25,99};
struct student *pst;
pst = &st;
printf("%d,%s,%d,%f\n",st.sno,st.name,st.age,st.score);
printf("%d,%s,%d,%f\n",(*pst).sno,(*pst).name,(*pst).age,(*pst).score);
printf("%d,%s,%d,%f\n",pst->sno,pst->name,pst->age,pst->score);
return 0;
}
8、结构体成员类型:
1》基本类型:
struct A{
int a;
float b;
};
2》数组:
struct A{
int a[5];
float b;
};
3》结构体:
#include <stdio.h>
struct A{
int a;
float b;
};
#if 0
struct B{
int x;
struct A y; //用已有的结构体类型定义成员变量
};
#else
struct B{
int x;
//定义一个新的结构体类型同时定义该结构体变量
struct {
int a;
float b;
}y;
};
#endif
int main(void)
{
struct B st = {100,{123,34.56}};
printf("%d,%d,%f\n",st.x,st.y.a,st.y.b);
return 0;
}
4》指针:
#include <stdio.h>
struct A{
int a;
int *p;
};
int main(void)
{
int x = 123;
struct A st = {100,&x};
printf("%d,%d\n",st.a,*st.p);
return 0;
}
5》结构体指针:
例1:
#include <stdio.h>
struct A{
int a;
float b;
};
struct B{
int x;
struct A *pst;
};
int main(void)
{
struct A sta = {123,3.5};
struct B stb = {100,&sta};
printf("%d\n",stb.x);
printf("%d,%f\n",stb.pst->a,stb.pst->b);
return 0;
}
例2:
#include <stdio.h>
typedef struct B{
int x;
struct B *pst;
}ST;
typedef struct node{
int data;
struct node *next;
}list,*plist;
int main(void)
{
ST st1 = {100,NULL};
ST st2 = {200,&st1};
ST st = {300,&st};
list nd = {1000};
plist pnd = &nd;
printf("pnd->data = %d\n",pnd->data);
printf("%d\n",st2.x);
printf("%d\n",st2.pst->x);
printf("%d,%d\n",st.x,st.pst->x);
return 0;
}
二、共用体
也叫联合体,是一种复合数据类型,C语言中也没有该类型的具体定义,但是给出了定义该类型的语法格式
也是由不同类型数据组成,但是共用体中的多个数据共同使用同一块内存空间。
1、共用体类型的定义
union <共用体标签>{
成员类型 成员名;
成员类型 成员名;
.... ....
成员类型 成员名;
};
例如:定义一个共用体的类型
union student{
int sno;
char name[20];
int age;
float score;
};
2、共用体变量的定义
1》常规定义:
union student{
int sno;
char name[20];
int age;
float score;
};
union student st1; //st1为共用体变量
2》与类型同时定义
union student{
int sno;
char name[20];
int age;
float score;
}st2; /st2为共用体变量
3》直接定义
union {
int sno;
char name[20];
int age;
float score;
}st3; /st3为共用体变量
3、使用
1》赋值和打印与结构体类似,例如:
#include <stdio.h>
#include <string.h>
//共用体类型的定义
union A{
short a;
char b[3];
char c[5];
};
int main(void)
{
union A u1;
printf("sizeof(union A) = %d\n",sizeof(union A));
printf("sizeof(u1) = %d\n",sizeof(u1));
printf("sizeof(u1.a) = %d\n",sizeof(u1.a));
printf("sizeof(u1.b) = %d\n",sizeof(u1.b));
printf("sizeof(u1.f) = %d\n",sizeof(u1.c));
#if 0
/*************************************/
u1.b = 12.34;
strcpy(u1.c,"hello");
u1.a = 123;
printf("u1.a = %d\n",u1.a);
printf("u1.b = %f\n",u1.b);
printf("u1.c = %s\n",u1.c);
/*************************************/
strcpy(u1.c,"hello");
u1.a = 123;
u1.b = 12.34;
printf("u1.a = %d\n",u1.a);
printf("u1.b = %f\n",u1.b);
printf("u1.c = %s\n",u1.c);
/*************************************/
#endif
#if 0
u1.a = 123;
u1.b = 12.34;
strcpy(u1.c,"hello");
printf("u1.a = %d\n",u1.a);
printf("u1.b = %f\n",u1.b);
printf("u1.c = %s\n",u1.c);
#endif
return 0;
}
总结:
1》共用体的成员共同使用同一块内存空间
2》在程序中,某一时刻只有一个成员的值有效,即最后被赋值的成员有效
实例:
判断机器的字节序?
#include <stdio.h>
#include <string.h>
union A{
unsigned int word;
unsigned char byte;
};
int main(void)
{
union A u1;
u1.word = 0x12345678;
if(u1.byte == 0x12)
printf("大端序!\n");
else
printf("小端序!\n");
return 0;
}
三、枚举类型
该类型的本质是整型,为了提高程序额可读性,同时为了人为的程序中的一些数据规定一个取值的范围,而设计出这样的枚举类型,例如
在程序中表示一周的每一天,或者一年中的每个月都可以定义成枚举类型
1、枚举类型的定义
enum <枚举标签>{
枚举常量,
枚举常量,
.....
枚举常量
};
例如:
enum phone_color{
white, //枚举常量
black, //枚举常量
golden //枚举常量
};
默认情况下,枚举常量的值,从第一个开始依次是:0,1,2,3,....
enum phone_color color; //color为枚举变量,一般在程序中取枚举常量的值
#include <stdio.h>
#include <string.h>
enum phone_color{
white, //枚举常量
black, //枚举常量
golden //枚举常量
};
enum A{
a1 = 100,
a2,
a3,
a4 = 99,
a5,
a6
};
struct phone{
float value;
enum phone_color color;
};
int main(void)
{
printf("white : %d\n",white);
printf("black: %d\n",black);
printf("golden : %d\n",golden);
printf("a1 = %d\n",a1);
printf("a2 = %d\n",a2);
printf("a3 = %d\n",a3);
printf("a4 = %d\n",a4);
printf("a5 = %d\n",a5);
printf("a6 = %d\n",a6);
struct phone apple = {5000,white};
return 0;
}
四、地址对齐
1、自然对齐
在数据分配空间时,如果该数据的起始地址能够被它的长度整除,则就是自然对齐
2、数据的M值
如果该数据的长度小于机器字长,则M值为该数据的长度
如果该数据的长度大于等于机器字长,则M值为机器字长。
3、适当对齐
在数据分配空间时,如果该数据的起始地址能够被它的M值整除,则就是适当对齐
4、不同类型数据的对齐
1》基本类型数据
按M值适当对齐
2》数组:
按元素的M值对齐
4》共用体:
按共用体变量的M值对齐,即:成员中M值最大的
5》结构体:
按结构体变量的M值对齐,即:成员中M值最大的
五、LinuxC语言中的一些特殊函数
1、递归函数
如果一个函数体内部,调用它自己,则该函数称为递归函数,例如:
#include <stdio.h>
#if 0
void fun(int x,int y)
{
printf("%d\n",x+y);
}
void test(void)
{
int a = 3,b = 5;
fun(a,b);
}
#else
void test(int i)
{
printf("i = %d\n",i++);
if(i < 5)
test(i);
}
#endif
int fun(int n)
{
if(n == 1)
return 1;
else if(n > 1)
return n*fun(n-1);
else
return 1;
}
int main(void)
{
int n;
scanf("%d",&n);
printf("%d\n",fun(n));
return 0;
}
2、变参函数
调用时,可以传不同类型的参数或者传不同个数的参数,这样的函数称为变参函数。
int printf(const char *format, ...);
#include <stdio.h>
#include <stdarg.h>
void myprint(int n,...)
{
va_list p;
int i,t;
va_start(p,n); //对p初始化
for(i = 0; i < n; i++){
t = va_arg(p,int);
printf("%d\t",t);
}
printf("\n");
va_end(p);
}
int main(void)
{
myprint(5,1,2,3,4,5);
myprint(5,111,222,333,444,555);
myprint(10,1,2,3,4,5,6,7,8,9,10);
return 0;
}
3、回调函数
指的是函数调用的一种方式,简单来说:间接调用的函数称为回调函数,例如:
4、内联函数