根据变量的作用域,可以分为:
4> 枚举
// s3才是char *指针,s4只是char
String2 s3, s4;
/*
char *s3, s4;
char *s3;
char s4;
if (n <= 0) return 1;
return pow2(b, n-1) * b;
}
1.局部变量:
1>在函数(代码块)内部定义的变量,包括函数的形参
2>作用域:从定义变量的那一行开始,一直到代码块结束
3>生命周期:从定义变量的那一行开始分配存储空间,代码块结束后,就会被回收。
4>没有固定的初始值。
2.全局变量:
1>定义:在函数外面定义的变量
2>作用域:从定义变量的那一行开始,一直到文件结尾(能被后面的所有函数共享)
3>生命周期:程序一启动就会分配存储空间,程序退出时才会被销毁。
4>默认的初始值就是0。
代码示例:
//全局变量:a,b,c
//局部变量:v1,v2,i
#include<stdio.h>
int a=10;
int b,c=20;
int sum(int v1,int v2)
{
return v1+v2;
}
void test()
{
b++; //全局变量
int i=0; //局部变量,每次调用都为初值0
i++;
printf("b=%d,i=%d\n",b,i);
}
int main()
{
//调用3次
test(); //1,1
test(); //2,1
test(); //3,1
}
构造类型:
数组:只能由多个相同类型的数据构成
结构体:可以由多个不同类型的数据构成
#include<stdio.h>
int main()
{
//1.定义结构体类型
struct Person
{ //里面的3个变量,可以称为是结构体的成员或者属性
int age;
double height;
char *name;
};
//2.根据结构体类型,定义结构体变量
struct Person p ={20,1.55,"jack"};
p.age =30; //
p.name = "rose";
printf("age=%d,name=%s,height=%f\n",p.age,p.name,p.height);
/*
错误写法,必须在定义变量时,为其赋值
struct Person p2;
p2={40,1.23,"fuck"};
*/
struct Person p2={.height=1.24,.name="tom",.age=30};
return 0;
}
内存分析
void test()
{
{
//1.定义结构体类型(并不会分配存储空间)
struct Date
{
int year;
int month;
int day;
};
// 2.定义结构体变量(真正分配存储空间)
struct Date d1 = {2011, 4, 10};
struct Date d2 = {2012, 8, 9};
// 会将d1所有成员的值对应地赋值给d2的所有成员
d2 = d1;
struct Date
{
int year;
int month;
int day;
};
// 2.定义结构体变量(真正分配存储空间)
struct Date d1 = {2011, 4, 10};
struct Date d2 = {2012, 8, 9};
// 会将d1所有成员的值对应地赋值给d2的所有成员
d2 = d1;
//只是修改d2对应的year的值,不会影响到d1
d2.year = 2010;
d2.year = 2010;
}
补齐算法(对齐算法),其结构体占用空间为最大成员占用空间的倍数。
struct Student
{
int age; //4个字节
char *name; //8个字节
};
struct Student stu;
stu.age=20;
stu.name="jack";
stu占用16个字节
定义变量的多种方式:
定义变量的第1种方式:先定义类型,再定义变量(分开定义)
//1.类型
struct Student
{
int age;
};
//2.变量
struct Student stu;
定义变量的第2种方式:定义类型的同时定义变量
这段代码做了两件事情
1.定义结构体类型
2.利用新定义好的类型来定义变量
struct Student
{
int age;
}stu;
struct Student stu2;
定义结构体变量的第3种方式:定义类型同时定义变量(省略了类型名称)
struct {
int age;
}stu;
缺点:不能重用
结构体类型不能重复定义
struct Student
{
int age;
};
struct Student
{
double height;
};
struct Student stu;
错误写法:结构体类型重复定义
struct Student
{
int age;
} stu;
struct Student
{
int age;
} stu2;
struct Student
{
int age;
};
struct Student
{
double height;
};
struct Student stu;
错误写法:结构体类型重复定义
struct Student
{
int age;
} stu;
struct Student
{
int age;
} stu2;
结构体类型作用域,从定义类型的那一行开始,一直到代码块结束。
1> 定义在函数外面:全局有效(从定义类型的那行开始,一直到文件结尾)
2> 定义在函数(代码块)内部:局部有效(从定义类型的那行开始,一直到代码块结束)
结构体数组
struct RankRecord
{
int no; // 序号 4
int score; // 积分 4
char *name; // 名称 8
};
{
int no; // 序号 4
int score; // 积分 4
char *name; // 名称 8
};
每个结构体变量占用16个字节
struct RankRecord records[3] =
{
{1, "jack", 5000},
{2, "jim", 500},
{3, "jake",300}
};
{
{1, "jack", 5000},
{2, "jim", 500},
{3, "jake",300}
};
//相当于 int age[3] = {19,20,21}
records[0].no = 4;
// 错误写法
//records[0] = {4, "rose", 9000};
// 错误写法
//records[0] = {4, "rose", 9000};
for (int i = 0; i<3; i++)
{
printf("%d\t%s\t%d\n", records[i].no, records[i].name, records[i].score);
}
{
printf("%d\t%s\t%d\n", records[i].no, records[i].name, records[i].score);
}
结构体指针
1.指向结构体的指针的定义
struct Student *p;
2.利用指针访问结构体的成员
1> (*p).成员名称
2> p->成员名称
struct Student *p;
2.利用指针访问结构体的成员
1> (*p).成员名称
2> p->成员名称
struct Student
{
int no;
int age;
};
// 结构体变量
struct Student stu = {1, 20};
// 指针变量p将来指向struct Student类型的数据
struct Student *p;
// 指针变量p指向了stu变量
p = &stu;
p->age = 30;
// 第一种方式
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);
{
int no;
int age;
};
// 结构体变量
struct Student stu = {1, 20};
// 指针变量p将来指向struct Student类型的数据
struct Student *p;
// 指针变量p指向了stu变量
p = &stu;
p->age = 30;
// 第一种方式
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 ruxueDate; // 入学日期
// 这种写法是错误的,不能在结构体内包含自己
//struct Student stu;
};
struct Student stu = {1, {2000, 9, 10}, {2012, 9, 10}};
printf("year=%d,month=%d,day=%d\n", stu.birthday.year, stu.birthday.month, stu.birthday.day);
{
int year;
int month;
int day;
};
// 类型
struct Student
{
int no; // 学号
struct Date birthday; // 生日
struct Date ruxueDate; // 入学日期
// 这种写法是错误的,不能在结构体内包含自己
//struct Student stu;
};
struct Student stu = {1, {2000, 9, 10}, {2012, 9, 10}};
printf("year=%d,month=%d,day=%d\n", stu.birthday.year, stu.birthday.month, stu.birthday.day);
枚举
用于变量有固定几个取值时。
enum Sex { Man, Woman, Unkown};
// 1.定义枚举类型
enum Season
{ //整型常量
spring ,
summer,
autumn,
winter
};
{ //整型常量
spring ,
summer,
autumn,
winter
};
// 2.定义枚举变量
enum Season s =spring;
enum Season s =spring;
总结:
一、基本数据类型
1.int
1> long int、long:8个字节 %ld
2> short int、short:2个字节 %d %i
3> unsigned int、unsigned:4个字节 %zd
4> signed int、signed、int:一样,4个字节 %d %i
2.float\double 小数
1> float :4个字节 %f 小数位少
2> double:8个字节 %f 小数位多 %.2f保留两位小数
3.char
1> 1个字节 %c %d
2> char类型保存在内存中的是它的ASCII值
'A' --> 65
二、构造类型
1.数组
1> 只能由同一种类型的数据组成
2> 定义:数据类型 数组名[元素个数];
1.int
1> long int、long:8个字节 %ld
2> short int、short:2个字节 %d %i
3> unsigned int、unsigned:4个字节 %zd
4> signed int、signed、int:一样,4个字节 %d %i
2.float\double 小数
1> float :4个字节 %f 小数位少
2> double:8个字节 %f 小数位多 %.2f保留两位小数
3.char
1> 1个字节 %c %d
2> char类型保存在内存中的是它的ASCII值
'A' --> 65
二、构造类型
1.数组
1> 只能由同一种类型的数据组成
2> 定义:数据类型 数组名[元素个数];
int age[3];
2.结构体
1> 可以由不同类型的数据组成
2> 先定义类型,再利用类型定义变量
三、指针类型
1.变量的定义
int *p;
2.间接操作变量的值
int a = 10;
p = &a;
*p = 20;
四、枚举类型
使用场合:当一个变量只允许有几个固定取值
2.结构体
1> 可以由不同类型的数据组成
2> 先定义类型,再利用类型定义变量
三、指针类型
1.变量的定义
int *p;
2.间接操作变量的值
int a = 10;
p = &a;
*p = 20;
四、枚举类型
使用场合:当一个变量只允许有几个固定取值
宏定义
1.所有的预处理指令都是以#开头
2.预处理指令分3种
1> 宏定义
2> 条件编译
3> 文件包含
3.预处理指令在代码翻译成0和1之前执行
4.预处理的位置是随便写的
5.预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾,可以用#undef取消宏定义的作用
6.宏名一般用大写或者以k开头,变量名一般用小写,规范问题!
2.预处理指令分3种
1> 宏定义
2> 条件编译
3> 文件包含
3.预处理指令在代码翻译成0和1之前执行
4.预处理的位置是随便写的
5.预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾,可以用#undef取消宏定义的作用
6.宏名一般用大写或者以k开头,变量名一般用小写,规范问题!
#define COUNT 4
char *name = "COUNT";
printf("%s\n", name);
int ages[COUNT] = {1, 2, 67, 89};
for ( int i = 0; i<COUNT; i++) {
printf("%d\n", ages[i]);
}
// 从这行开始,COUNT这个宏就失效
#undef COUNT
int a = COUNT;
printf("%s\n", name);
int ages[COUNT] = {1, 2, 67, 89};
for ( int i = 0; i<COUNT; i++) {
printf("%d\n", ages[i]);
}
// 从这行开始,COUNT这个宏就失效
#undef COUNT
int a = COUNT;
带参数的宏定义
带参数的宏定义效率比函数高,宏定义的本质是是
替换,并不会运算。
#define sum(v1, v2) ((v1)+(v2))
#define pingfang(a) ((a)*(a))
int c = pingfang(5+5)/pingfang(2);
int c = sum(2, 3) * sum(6, 4);
typedef 起别名
1.作用:给已经存在的类型起一个新的名称
2.使用场合:
2.使用场合:
1> 基本数据类型
typedef int MyInt;
MyInt i = 10;
2> 指针
typedef char * String;
String name = "jack";
3> 结构体
struct Student
{
int age;
};
typedef struct Student MyStu;
{
int age;
};
typedef struct Student MyStu;
---------------------------------------------
typedef struct Student
{
int age;
} MyStu;
{
int age;
} MyStu;
-----------------------------------------
typedef struct
{
int age;
} MyStu;
{
int age;
} MyStu;
-----------------------------------------
struct Person
{
int age;
};
typedef struct Person * PersonPoint;
{
int age;
};
typedef struct Person * PersonPoint;
-----------------------------------------------
typedef struct Person
{
int age;
} * PersonPoint;
{
int age;
} * PersonPoint;
4> 枚举
enum Sex {Man, Woman};
typedef enum Sex MySex;
typedef enum Sex MySex;
-----------------------------------------
typedef enum {
Man,
Woman
} MySex;
5> 指向函数的指针
Man,
Woman
} MySex;
5> 指向函数的指针
typedef int (*MyPoint)(int, int);
int minus(int a, int b)
{
return a - b;
}
int sum(int a, int b)
{
return a + b;
}
{
return a - b;
}
int sum(int a, int b)
{
return a + b;
}
MyPoint p = sum;
MyPoint p2 = minus;
等同于如下两句:
MyPoint p2 = minus;
等同于如下两句:
//int (*p)(int, int) = sum;
//int (*p2)(int, int) = minus;
//int (*p2)(int, int) = minus;
p(10, 11);
--------------------------------
#define与typedef区别
#define只是纯粹的文本替换,typedef起别名其本质还是类型。
#define String2 char *
typedef char * String;
typedef char * String;
//s1、s2是char *指针
String s1, s2;
/*
String s1;
String s2;
*/
s1 = "jack";
s2 = "rose";
String s1, s2;
/*
String s1;
String s2;
*/
s1 = "jack";
s2 = "rose";
// s3才是char *指针,s4只是char
String2 s3, s4;
/*
char *s3, s4;
char *s3;
char s4;
条件编译 只要写了#if,在最后面必须加上#endif
#if (A == 10)
printf("a是10\n");
#elif (A == 5)
printf("a是5\n");
#else
printf("a其他值\n");
#endif
printf("a是10\n");
#elif (A == 5)
printf("a是5\n");
#else
printf("a其他值\n");
#endif
--------------------------------
如果没有宏定义
//#define A 5
#ifndef A
//#ifdef A
//#if !defined(A)
printf("哈哈\n");
#endif
//#ifdef A
//#if !defined(A)
printf("哈哈\n");
#endif
递归
递归的2个条件:
1.函数自己调用自己
2.必须有个明确的返回值
1.函数自己调用自己
2.必须有个明确的返回值
例子:设计一个函数,用来计算b的n次方
普通的for循环
int pow2(int b, int n)
{
for (int i = 0; i<n; i++)
{
result *= b;
}
{
result *= b;
}
}
运用递归
int pow2(int b, int n)
{
if (n <= 0) return 1;
return pow2(b, n-1) * b;
}