指针
- 指针与函数
#include <stdio.h>
void test();
int main()
{
/*
* 指向函数的指针
* 计算机也会给函数分配存储空间,所以函数也有自己的地址,所以指针
* 变量也可以保存函数的地址
*
* 数组名保存的就是数组的地址,函数名中保存的也是函数的地址
*
* 如何定义函数指针变量
* 1. 将需要函数拷贝
* 2. 在函数返回值和函数名之间加*
* 3. 修改函数名称
* 4. 需要将*和变量名称用括号括起来
*
* 注意点:
* 如果是数组,我们可以直接将数组名称赋值给一个指针变量
* 如果是函数,我们可以直接将函数名称赋值给一个指针变量
*/
//定义函数指针变量
void (*funcp)();
//将函数的地址赋值给函数指针
// funcp = &test;
funcp = test; //因为函数名称保存的是地址,所以这种写法也可以
//test(); //调用函数的第一种方式
//(*funcp)(); //调用函数的第二种方式
funcp(); //调用函数的第三种方式
return 0;
}
void test(){
printf("打印点东西");
}
- 练习
回调函数
#include <stdio.h>
int sum(int, int);
int minus(int, int);
int main()
{
/*
* 需求: 要求一个函数既可以计算两个变量的和也可以计算两个变量的差
*/
int res = test(10, 20, minus);
printf("%i\n", res);
return 0;
}
/*
* 注意点: 指向函数的指针,作为函数的形参的时候,指针变量的名称,就是形参名称
* 如果指向函数的指针作为函数的形参,那么这个函数可以称之为回调函数
*/
int test(int a, int b, int (*funcp)(int ,int)){
return funcp(a, b);
}
int sum(int a,int b){
return a + b;
}
int minus(int a, int b){
return a - b;
}
结构体
- 基本概念
/*
* 结构体
* 结构体是构造类型的一种,数组也是构造类型,数组的作用是存储一组相同
* 类型的数据,结构体的作用是存储一组不同类型的数据
*
* 如何定义结构体变量
* 1. 先定义结构体的类型
* 2. 通过结构体的类型定义结构体的变量
*
* 定义结构体的类型
* struct 结构体类型名称{
* 数据类型 属性名称;
* 数据类型 属性名称;
* .
* .
* }
*
* 定义结构体变量
* struct 结构体类型名称 变量名称;
*
* 访问结构体属性
* 结构体变量名称.结构体属性名称;
*/
//定义结构体的类型
struct Person{
char *name;
int age;
double height;
};
//定义结构体变量
struct Person p;
//使用结构体变量
p.name = "niuzi";
p.age = 18;
p.height = 1.6;
printf("%s\n", p.name);
printf("%i\n", p.age);
printf("%lf\n", p.height);
- 结构体变量初始化
/*
* 结构体的初始化
* 1. 定义的同时初始化
* 2. 先定义后初始化
* 3. 先定义结构体变量,后再完全初始化,但是不建议这样写
*/
struct Dog
{
char *name;
int age;
};
//1. 先定义后初始化
// struct Dog p;
// p.name = "ww";
// p.age = 10;
//2. 定义的同时初始化
//注意点: 定义的同时初始化,那么初始化顺序必须和结构体类型中的顺序一致
// struct Dog p ={"ww", 10};
struct Dog p ={.name = "ww", .age = 10}; //这种顺序可以变
- 定义结构体变量
/*
* 定义结构体变量的几种方式
* 1. 先定义结构体类型,再定义结构体变量
* 2. 定义结构体类型的同时定义结构体变量
* 3. 定义结构体类型的同时省略结构体名称,同时定义结构体变量
*/
//1.先定义结构体类型,再定义结构体变量
// struct Person
// {
// char *name;
// int age;
// };
// struct Person p;
//2. 定义结构体类型的同时定义结构体变量
struct Person
{
char *name;
int age;
} p2;
p2.age = 18;
p2.name = "ll";
printf("%i\n", p2.age);
//3. 定义结构体类型的同时省略结构体名称,同时定义结构体变量
//匿名结构体,结构体类型只能使用一次
struct
{
char *name;
int age;
} p3;
结构体变量作用域
结论; 和变量的作用域一样,在代码块中只能在该代码块中使用,外界无法访问的到
结构体数组
定义一个数组保存结构体变量
/*
* 结构体数组
* 结构体类型 数组名称[元素个数];
*/
struct Person
{
char *name;
int age;
};
struct Person p1 = {"ww", 16};
struct Person p2 = {"jj", 18};
struct Person p3 = {"nn", 20};
//结构体数组第一种方式
struct Person ps[3] = {p1, p2, p3};
//结构体数组第二种方式
struct Person ps[3] = {
{"ww", 16},
{"jj", 18},
{"nn", 20}
};
-
结构体内存分析
/*
* 结构体内存分析
*/
/*
* 结构体在分配内存的时候,会做一个内存对齐操作
* 会先获取所有属性中内存最大的属性的字节,然后在开辟最大属性字节的内存给第一个属性
* 之后再分配给第二个属性,如果分配的内存存储第一个属性后,不够第二个属性存储
* 那么会再次开辟最大属性字节的内存,再往后分配
*
*/
struct Person
{
char *name;
int score;
};
//结构体在分配内存的时候,会做一个内存对齐的操作,会按照结构体属性当中
// 占用内存最大的那个字节属性的字节倍数来分配
struct Person p;
printf("sizeof = %i\n", sizeof(p)); //8
//结构体变量名称没有保存结构体首属性的地址
printf("p = %p\n", p); //00000054
printf("&p = %p\n", &p); //0028FEB8
printf("p.name = %p\n", &p.name); //0028FEB8
printf("p.score = %p\n", &p.score); //0028FEBC
- 结构体指针
/*
* 结构体指针
* 定义指向结构体变量的指针的套路和过去定义指向普通变量一样
*
* 如果指针指向了一个结构体变量,那么访问结构体属性就有三种方式
* 1. 结构体变量名称.属性名称
* 2. (*结构体指针变量名称).属性名称
* 3. 结构体指针变量->属性名称
*/
struct Person
{
char *name;
int age;
};
struct Person per = {"niuzi", 18};
//定义结构体指针
struct Person *p;
p = &per;
//指针两种访问属性方式
printf("%s\n", (*p).name);
printf("%i\n", p->age);
- 结构体嵌套
/*
* 结构体嵌套
* 可以提高代码的复用率
*/
//1. 定义一个日期的结构体
struct Date
{
int year;
int month;
int day;
};
//2. 定义一个人的结构体
struct Person
{
char *name;
int age;
struct Date birthday; //结构体嵌套
};
//结构体嵌套初始化
struct Person per = {"ww", 18, {2008,10,23}};
printf("%i\n", per.birthday.year); //访问嵌套属性
printf("%i\n", per.birthday.month);
printf("%i\n", per.birthday.day);
- 结构体和函数
注意点: 结构体变量之间是值传递,和普通变量一样
/*
* 结构体和函数
* 结构体是构造类型,但是结构体变量之间是值传递,和普通变量一样
*
* 注意点: 定义结构体类型的时候不会分配存储空间,只有定义结构体变量
* 的时候才会分配存储空间
*/
struct Person
{
char *name;
};
struct Person p1 = {"nn"};
struct Person p2;
p2 = p1; //值传递
p2.name = "haha";
printf("p1 = %s\n", p1.name); //nn
printf("p2 = %s\n", p2.name); //haha
#include <stdio.h>
struct Person
{
char *name;
};
void test(struct Person per);
int main()
{
/*
* 结构体和函数
* 结构体是构造类型,但是结构体变量之间是值传递,和普通变量一样
*
* 注意点: 定义结构体类型的时候不会分配存储空间,只有定义结构体变量
* 的时候才会分配存储空间
*/
// struct Person
// {
// char *name;
// };
// struct Person p1 = {"nn"};
// struct Person p2;
// p2 = p1; //值传递
// p2.name = "haha";
// printf("p1 = %s\n", p1.name); //nn
// printf("p2 = %s\n", p2.name); //haha
struct Person p1 = {"nn"};
test(p1);
printf("p1 = %s\n", p1.name);
return 0;
}
/*
* 在main函数中结构体是局部,外部函数无法访问所以要放到外面
* 结构体变量是值传递,不是传递地址,所以函数内部无法改变结构体的属性
*/
void test(struct Person pe){
pe.name = "zs";
}