------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
黑马程序员-iOS基础-C语言基础(六)
复杂数据类型及其他
一、复杂数据类型
1、变量类型(根据变量作用域)
变量类型 | 定义 | 作用域 | 生命周期 | 初始值 |
局部变量 | 在代码块内部定义的变量 | 从定义的那一行到代码块结束 | 从定义的那一行开始分配存储空间,代码块结束后就会被回收 | 没有固定的初始值 |
全局变量 | 在函数外定义的变量 | 从定义的那一行开始一直到文件结尾 | 程序启动就会分配存储空间,程序退出时才会被销毁 | 默认初始值是0 |
2、构造类型
1)数组:多个同一类型的数据组成
2)结构体Struct:由多个不同类型的数据构成
定义结构体的步骤:a.定义结构体类型(结构体类型默认是不存在的);b.根据结构体类型,定义结构体变量。
举例:
//定义结构体类型
struct Person
{ //里面的3个变量,可以称为结构体的成员或者属性
int age;
double height;
char *name;
};
//根据结构体类型,定义结构体变量
struct Person p={20,1.55,"jack"};
或
p.age=30;
p.name="rose";
注意:
//这种赋值方式是错误的
struct Person p2;
p2={30,1.67,"jack"};
//只能在定义的同时一次性赋值
//或者分开赋值
//如下
struct Person p2={.height=1.78,.name="rose",.age=18);
练习:日期结构体
int main()
{
//定义结构体类型,并不会分配存储空间
struct Date
{
int year;
int month;
int day;
};
//定义结构体变量(真正分配存储空间)
struct Date d1={2011,9,10};
return 0;
}
内存分析
结构体所占用的内存空间大小等于其中所有成员占用内存的和
注意:补齐算法/对齐算法:结构体所占内存是最大成员的倍数
结构体之间赋值
会把赋值的结构体的所有成员的值对应的赋值给被赋值的所有成员
结构体注意点
a.结构体的多种定义方式
第一种方法
struct Student//定义结构体类型
{
int age;
double height;
char *name;
};
struct Student stu={20,1.78,"jack"};//定义结构体变量
第二种方法//定义结构体类型的同时定义结构体变量
struct Student
{
int age;
double height;
char *name;
} stu;
第三种方法//缺点不能重用
struct {
int age;
char *name;
}stu;
b.作用域
定义在代码块内:结构体也有作用域,从定义的那一行开始,到代码块结束
定义在函数外面,全局有效:从定义的那一行开始直到文件结尾
c.不可以自己包含自己
结构体数组
举例:
struct RankRecord{
int no;
char *name;
int score;
};
struct RankRecord records[3]=
{
{1,"Jack",5000},
{2,"Jim",500},
{3,"Jake",300},
};
for(int i=0;i<3;i++)
{
printf("%d\t%s\t%d\n",records[i].no,records[i].name,records[i].score);
}
指向结构体的指针:利用指针访问结构体的成员
举例:
struct Student { //定义结构体
int no;
int age;
};
struct Student stu={1,20};//定义结构体变量
struct Student *p;//定义指向结构体的指针p
p=&stu;//p指向stu
//第一种方式
printf("age=%d,no=%d\n",stu.age,stu.no);
//第二种方式
printf("age=%d,no=%d\n",(*p).age,(*p).no);
//第三种方式
printf("age=%d,no=%d\n",p->age,p->no);//最常用
结构体的嵌套
举例:
struct Date{
int year;
int month;
int day;
};
struct Student
{
int no;
struct Date birthday;
struct Date enterday;
};
struct Student stu={1,{2000,9,10},{2012,4,10}};
3)枚举类型
场合:当一个变量只有几个固定取值时
举例:
定义枚举类型
enum Season
{
spring,summer,autumn,winter
};
定义枚举变量
enum Season s=summer;
二、数据结构总结
1、基本数据类型
基本数据类型 | 占用内存字节数 | 输出占位符 | 备注 |
long | 8 | %ld | |
short | 2 | %d | |
signed(int) | 4 | %d | 与int类型一致 |
unsigned | 4 | %zd | |
float | 4 | %f | |
double | 8 | %f | |
char | 1 | %c | 保存在内存中的是它的ASCII码值 |
2、构造类型
由基本数据类型构成
数组: 多个同一类型的数据组成
结构体: 可以由多个不同类型的数据构成
3、指针类型
定义方式:举例:int *p
间接操作变量的值,举例:
int a=10;
p=&a;
*p=20
4、枚举类型
三、其他
1、预处理指令
作用:在代码编译成0和1之前把代码中的对应指令进行更换
预处理的位置是随意可选的,但是有作用域:从编写指令的那一行开始到文件结尾
特点:都以#开头
宏定义
定义: #define 宏名 值
宏名一般都大写或以k开头,变量名一般用小写
不带参数的宏定义
#define COUNT 5
出现在双引号内的指令不会更换
取消定义 #undef COUNT
从这一行开始,COUNT这个宏失效
带参数的宏定义
举例:求和
#define sum(v1,v2) v1+v2
int c=sum(2,3)*sum(6+4)
c=24;
参数都带括号,结果也带括号
效率比函数高
条件编译
格式
//条件一般要判断宏,不能使用函数中的变量
#if (条件){}
#elif (条件){}
#else{}
#endif
//写了#if一定有#endif配对
#ifdef
#ifndef
#if defined与#ifdef基本相同
文件包含
#include
注意
a. <>表示系统自带文件,""表示自定义文件
b. 不允许循环包含
c. 编译时要把所有文件一起编译链接
保证文件头文件内容只拷贝一次的方法
#ifndef ABC
#define ABC xxx
.....
#endif
对以上代码中的ABC在每个文件中必须不一样,否则会出错
2、typedef类型声明
作用:给已经存在的类型起一个新的名称
举例:typedef int MyInt
typedef char * String
结构体
struct Student
{ int age; };
typedef struct Student MyStu;
//或
typedef struct Student
{ int age; }MyStu;
MyStu stu={20};
枚举
enum Sex {Man,Woman};
typedef enum Sex MySex;
//或
type enum Sex{
Man,
Woman
}MySex;
指向函数的指针
int minus(int a,int b)
{return a-b;}
int sum(int a,int b)
{return a+b;}
typedef int (*MyPoint)(int,int);
int main()
{
MyPoint p=sum;
MyPoint p2=minus;
return 0;
}
指向结构体的指针
struct Person
{int age;};
typedef struct Person * PersonPoint;
int main()
{
struct Person p={20};
PersonPoint p2=&p;
return 0;
}
或
typedef struct Person
{int age;} * PersonPoint;
使用场合:
基本数据类型;
指针
结构体
枚举
指向函数的指针
3、static和extern的作用
外部函数:定义的函数能被本文件和其他文件访问,关键字extern
内部函数:定义的函数只能被本文件访问,其他文件不能访问,关键字static
注意:默认情况下所有函数都是外部函数;不允许有同名的外部函数。
extern对函数的作用
完整的定义一个外部函数
完整的声明一个外部函数
可以省略
static对函数的作用
定义一个内部函数
声明一个内部函数
全局变量
外部变量:定义的变量能被本文件和其他文件访问
默认情况下,所有的全局变量都是外部变量
不同文件中的同名外部变量,都代表同一个变量
内部变量:定义的变量只能被本文件访问,不能被其他文件访问
不同文件中的同名内部变量互不影响
从定义的那一行到文件结尾有效
extern:声明一个外部变量
static:定义一个内部变量
局部变量
static修饰局部变量,延长局部变量的生命周期,程序结束时,局部变量才会被销毁,没有改变局部变量的作用域
使用场合:某个函数的调用频率特别高
该函数内部的某个变量值是固定不变的
4、递归
举例:求一个数的n次方
#include <stdio.h>
int pow2(int b,int n)
int main()
{
int c=pow2(2,5);
printf("%d\n",c);
return 0;
}
int pow2(int b,int n)
{
if(n<=0) return 1;
return pow2(b,n-1)*b;
}
使用递归的条件
1.函数自己调用自己
2.必须有个明确的返回值