Day 11
文章目录
-
- 内存分区代码分析
- 结构体
- 结构体和指针
- 技术细节
- 小结
内存分区代码分析
返回栈区地址

#include<stdio.h>
int *fun()
{
int a = 10;
return &a;
}
int main()
{
int *p =NULL;
p = fun();
*p = 100; //操作野指针指向的内存,err
return 0;
}
返回data区地址
#include<stdio.h>
int *fun()
{
static int a = 10;
return &a;//a不释放
}
int main()
{
int *p = NULL;
p = fun();
*p = 100; //ok
printf("*p = %d\n",*p);
return 0;
}
值传递

#include<stdio.h>
#include<stdlib.h>
void fun(int *tmp)
{
tmp = (int *)malloc(sizeof(int));
*tmp = 100;
}
int main()
{
int *p = NULL;
fun(p); //值传递,形参不会影响实参!!!
printf("*p = %d\n",*p); //err//操作空指针指向的内存
return 0;
}
值传递2

#include<stdio.h>
void fun(int *tmp)
{
*tmp = 100;
}
int main()
{
int *p = NULL;
p = (int *)malloc(sizeof(int));
fun(p); //值传递
printf("*p = %d\n",*p); //ok
return 0;
}
返回堆区地址
#include<stdio.h>
#include<stdlib.h>
int *fun()
{
int *tmp = NULL;
tmp = (int*)malloc(sizeof(int));
*tmp = 100;
return tmp;
//返回堆区地址,函数调用完毕,不释放
}
int main()
{
int *p = NULL;
p = fun();
printf("*p = %d\n",*p); //ok
//堆区空间,使用完毕,手动释放
if(p != NULL)
{
free(p);
p = NULL;
}
return 0;
}
结构体
结构体的基本操作
#include<stdio.h>
#include<string.h>
//定义一个结构体类型
//1、struct是关键字
//2、struct Student合起来才是结构体类型
//3、结构体内部定义的变量不能直接赋值
//4、结构体只用一个类型,没有定义变量前,是没有分配空间,没有空间,就不能赋值
struct Student
{
int age;
char name[50];
int score;
};//有分号
int main()
{
//定义结构体变量
//1、类型名 变量名
struct Student sru;//别忘了struct关键词
//1、结构体变量初始化,和数组一样,要使用大括号
//2、只有在定义时才能初始化
struct Student sru2 = {18,"mike",60};
struct Student tmp;
//如果是普通变量,使用,点运算符
tmp.age = 19;
//tmp.name = "mike";//name成员是数组名,数组名是常量,不能修改
strcpy(tmp.name,"mike");
tmp.score = 60;
//如果是指针变量,使用->
//如果是指针,指针有合法指向,才能操作结构体成员
struct Student *p;
p = &tmp;
p -> age = 18;
strcpy(p->name,"mkie");
p -> score = 60;
//任何结构体变量都可用.或者->操作成员
(&tmp)->age = 18;
(*p).age = 18;
p[0].age = 18;
return 0;
}
结构体使用画图

结构体变量使用补充
#include<stdio.h>
struct Student
{
int age;
char name[50];
int score;
}s1 = {18,"mike",60},s2;
struct
{
int age;
char name[50];
int score;
}s3,s4;
int main()
{
printf("%d,%s,%d\n",s1.age,s1.name,s1.score);
return 0;
}
结构体数组
#include<stdio.h>
#include<string.h>
struct Student
{
int age;
char name[50];
int score;
};
int main()
{
struct Student s;
struct Student a[5]; //结构体数组
//操作元素
a[0].age = 18;
strcpy(a[0].name,"mike");
a[0].score = 80;
//操作某个元素地址
(a+1)->age = 18;
strcpy((a+1)->name,"jiang");
(a+1)->score = 60;
//操作元素
(*(a+2)).age = 20;
strcpy((*(a+2)).name,"fee");
(*(a+2)).score = 59;
struct Student *p = a;
p[3].age = 21;
strcpy(p[3].name,"xiang");
p[3].score = 54;
(p+4)->age = 22;
strcpy((p+4)->name,"fei");
(p+4)->score = 66;
int i = 0;
int n = sizeof(a)/sizeof(a[0]);
for(i = 0;i < n;i++)
{
printf("%d,%s,%d\n",a[i].age,a[i].name,a[i].score);
}
return 0;
}
int main02()
{
struct Student a1[5] =
{
{18,"mike",80},
{18,"jiang",60},
{20,"fee",59},
{21,"xiang",54},
{22,"fei",66}
};
struct Student a2[5] =
{
18,"mike",80,
18,"jiang",60,
20,"fee",59,
21,"xiang",54,
22,"fei",66
};
struct Student a3[5] =
{18,"mike",80,18,"jiang",60,20,"fee",59,21,"xiang",54,22,"fei",66
};
//求平均分
int i = 0;
int n = sizeof(a1)/sizeof(a1[0]);
int sum = 0;
for(i = 0;i < n;i++)
{
sum+=a1[i].score;
}
printf("平均分: %d\n",sum)
return 0;
}
结构体嵌套
#include<stdio.h>
#include<string.h>
struct Info
{
int age;
char name[50];
};
struct Student
{
struct Info info;
int score;
};
int main()
{
struct Student s;
s.info.age = 18;
strcpy(s.info.name,"mike");
s.score = 69;
struct Student *p = &s;
p->info.age = 18;
strcpy(p->info.name,"mike");
p->score = 69;
struct Student tmp = {18,"mike",69};
printf("%d,%s,%d\n",tmp.info.age,tmp.info.name,tmp.score);
return 0;
}
结构体赋值
#include<stdio.h>
#include<string.h>
struct Student
{
int age;
char name[50];
int score;
};
int main()
{
int a = 10;
int b;
//把a的值赋给了b
b = a;
//1、相同类型的2个结构体变量可以相互赋值
//2、尽管2个结构体变量的内容一样,但是2个变量是没有关系的独立内存
struct Student s1 = {19,"mike",78};
struct Student s2;
s2 = s1;
printf("%d,%s,%d\n",s2.age,s2.name,s2.score);
return 0;
}
结构体值传递和地址传递区别

#include<stdio.h>
#include<string.h>
struct Student
{
int age;
char name[50];
int score;
};
void setStu(struct Student tmp)
{
tmp.age = 22;
strcpy(tmp.name,"jiang");
tmp.score = 66;
printf("setStu %d,%s,%d\n",tmp.age,tmp.name,tmp.score);
}
int main()
{
struct Student s1 = {19,"mike",78};
setStu(s1);
printf("%d,%s,%d\n",s1.age,s1.name,s1.score);
return 0;
}
#include<stdio.h>
struct Student
{
int age;
char name[50];
int score;
};
void fun(struct Student tmp)
{
printf("%d,%s,%d\n",tmp.age,tmp.name,tmp.score);
}
void fun2(struct Student *p)
{
printf("%d,%s,%d\n",p->age,p->name,p->score);
}
void fun3(const struct Student *p)
{
printf("%d,%s,%d\n",p->age,p->name,p->score);
}
/*
void fun2(struct Student const *p)
{
printf("%d,%s,%d\n",p->age,p->name,p->score);
}
*/
int main()
{
struct Student s1 = {18,"mike",57};
//fun(s1);
fun2(&s1);
fun3(&s1);
return 0;
}
结构体和指针
指针指向栈区空间
#include<stdio.h>
#include<string.h>
struct Student
{
int age;
char name[50];
int score;
};
int main()
{
//定义一个结构体类型的指针
struct Student *p;
//在栈区定义一个结构体变量
struct Student tmp;
p = &tmp;
p->age = 18;
strcpy(p->name,"mike");
p->score = 89;
printf("%d,%s,%d\n",p->age,p->name,p->score);
printf("%d.%s,%d\n",tmp.age,tmp.name,tmp.score);
return 0;
}
指针指向栈区空间
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Student
{
int age;
char name[50];
int score;
};
int main()
{
struct Student *p;
//指针指向堆区空间
p = (struct Student *)malloc(sizeof(struct Student));
if(p == NULL)
{
printf("malloc err\n");
return 0;
}
p -> age = 18;
strcpy(p->name,"mike");
p->score = 89;
printf("%d,%s,%d\n",p->age,p->name,p->score);
if(p != NULL)
{
free(p);
p = NULL;
}
return 0;
}
非法使用内存导致的错误说明
#include<stdio.h>
#include<string.h>
struct Student
{
int age;
char name[50];
int score;
};
struct Test
{
char *str;
int a;
int b;
int c;
};
int main01()
{
struct Student s;
s.age = 18;
strcpy(s.name,"mike");
s.score = 59;
return 0;
}
int main()
{
struct Test obj;
strcpy(obj.str,"mike");//给str指向的内存拷贝内容
printf("str = %s\n",obj.str);
return 0;
}
成员指针指向data区或栈区
#include<stdio.h>
#include<string.h>
struct Student
{
int age;
char *name;
int score;
};
//成员变量指针指向文字常量区的字符串
int main()
{
struct Student s;
s.age = 18;
s.name = "mike"; //指针变量保存字符串常量的首地址
s.score = 69;
return 0;
}
#include<stdio.h>
#include<string.h>
struct Student
{
int age;
char *name;
int score;
};
//成员变量指针指向栈区空间
int main()
{
struct Student s;
s.age = 18;
char buf[100];
s.name = buf; //指针变量保存字符串常量的首地址
strcpy(s.name,"mike");
s.score = 69;
printf("buf = %s\n",buf);
return 0;
}
成员指针指向堆区空间
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Student
{
int age;
char *name;
int score;
};
//成员变量指针指向堆区空间
int main()
{
struct Student s;
s.age = 18;
// s.name = (char *)malloc((strlen("mikehelloworld")+1)*sizeof(char)); //char空间为1字节,可以忽略
s.name = (char *)malloc(strlen("mikehelloworld")+1);
strcpy(s.name,"mikehelloworld");
s.score = 69;
printf("%d,%s,%d\n",s.age,s.name,s.score);
if(s.name != NULL)
{
free(s.name);
s.name = NULL;
}
return 0;
}
结构体套一级指针
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Student
{
int age;
char *name;
int score;
};
int main()
{
struct Student *p;
//给p分配内存
p = (struct Student *)malloc(sizeof(struct Student));
if(p == NULL)
{
printf("分配失败\n");
return 0;
}
p->name = (char *)malloc(strlen("mike")+1);
p->age = 18;
strcpy(p->name,"mike");
p->score = 54;
printf("%d,%s,%d\n",p->age,p->name,p->score);
//先释放name
if(p->name != NULL)
{
free(p->name);
p->name = NULL;
}
//再释放p
if(p != NULL)
{
free(p);
p = NULL;
}
return 0;
}

结构体和指针结合使用总结
//1、指针指向栈区空间
struct Student *p;
struct Student tmp;
p = &tmp;
p->age = 18;
//2、指针指向栈区空间
struct Student *p;
p = (struct Student *)malloc(sizeof(struct Student));
p->age = 18;
//3、字符指针
//a、字符指针保证字符常量首元素地址
char *p;
p = "mike"; //ok
//b、指向栈区空间
char *p;
char buf[100];
p = buf;
p = &buf[0];
strcpy(p,"mike");//往p所指向的内存拷贝内容
//c、指向堆区空间
char *p;
p = (char *)malloc(strlen("mike")+1);
strcpy(p,"mike"); //往p所指向的内存拷贝东西
struct Student
{
int age;
char *name;
int score;
};
//4、结构体嵌套一级指针
//a、指针data区
struct Stududent obj;
obj.name = "mike";
//b、指向栈区空间
struct Student obj;
char buf[100];
obj.name = buf;
strcpy(obj.name,"mike");//往p所指向的内存拷贝内容
//c、指向堆区空间
struct Student obj;
obj.name = (char *)malloc(strlen("mike")+1);
strcpy(obj.name,"mike"); //往p所指向的内存拷贝东西
//d、参考结构体嵌套一级指针
共用体(联合体)
#include<stdio.h>
union Test
{
unsigned char a;
unsigned short b;
unsigned int c;
//double d;
};
int main()
{
//1、结构体的大小可以简单认为成员大小的累加
//2、共用体的大小为最大成员的大小
printf("%lu\n",sizeof(union Test));
//3、共用体公有一块内存,所有成员的地址都一样
union Test obj;
printf("%p,%p,%p,%p\n",&obj,&obj.a,&obj.b,&obj.c);
//4、给某个成员赋值,会影响到另外的成员
//左边是高位,右边是低位
//高位放高地址,低位放低
obj.c = 0x44332211;
printf("obj.c = %x\n",obj.c);
printf("obj.b = %x\n",obj.b);
printf("obj.a = %x\n",obj.a);
obj.a = 0xaa;
printf("obj.c = %x\n",obj.c);
printf("obj.b = %x\n",obj.b);
printf("obj.a = %x\n",obj.a);
obj.b = 0xccdd;
printf("obj.c = %x\n",obj.c);
printf("obj.b = %x\n",obj.b);
printf("obj.a = %x\n",obj.a);
return 0;
}
枚举的使用
#include<stdio.h>
/*
#define pink 0
#define red 1
#define white 3
#define blue 4
#define yellow 5
*/
//enum是关键字
//里面的成员是一个标示符,枚举常量
//第一个成员如果没有赋值,默认为0,下一个成员比上一个多1
//枚举类型enum Color
//成员:枚举成员,枚举常量
enum Color
{
pink,red,green=10,white,blue,yellow //可以对其进行初始化
};
int main()
{
int flag = 1;
if(flag == red)
{
printf("red\n");
}
//枚举变量flag2
enum Color flag2;
//1、可以使用枚举成员给flag2赋值
flag2 = pink; //等价于pink = 0
//2、也可以使用常量给flag2赋值,不推荐
flag2 = 3;
return 0;
}
typedef的使用
#include<stdio.h>
struct Test
{
int a;
};
//定义一个结构体变量
struct Test obj;
//给struct Test2类型起了一个别名叫Test2
typedef struct Test2
{
int a;
}Test2;
Test2 tmp;//少了struct
int main()
{
//1、typedef给一个以存在的类型起一个别名
//2、typedef不能创建新类型
typedef int int64; //有分号
int64 a; //int a; //宏定义发生在预处理
//typedef是在编译阶段
return 0;
}
课堂笔记
const修饰的结构体变量:
struct Student
{
int age;
char name[50];
int score;
};
struct Student tmp;
struct Student *p1 = &tmp;
p1->age = 18;//ok
p1 = NULL; //ok
//const修饰的是*,指针指向的内存不能修改
const struct Student *p2 = &tmp;
struct Student cosnt *p2 = &tmp;
p2->age = 18;//err
p2 = NULL;//ok
struct Student * const p2 = &tmp;
p2->age = 18; //ok
p2 = NULL; //err