CC++
计算机程序编译过程分为4个步骤:
- 预处理
- 编译
- 汇编
- 链接
[i->s->o]
预处理:gcc -E hello.c -o hello.i
编译:gcc –S hello.i –o hello.s 或 gcc –S hello.c –o hello.s
汇编:gcc –c hello.c –o hello.o 或 as hello.s –o hello.o
- (1).预处理,生成预编译文件(.i文件):
Gcc –E hello.c –o hello.i
- (2).编译,生成汇编代码(.s文件):
Gcc –S hello.i –o hello.s
- (3).汇编,生成目标文件(.o文件):
Gcc –c hello.s –o hello.o
- (4).链接,生成可执行文件:
Gcc hello.o –o hello
c语言数据类型:
基本类型:
数值类型:
整形:
1.短整型:short
2.整形:int
3.长整型:long
4.空类型:void
浮点型:
1.单精度型:float 有效位数6-7位,单精度数后需写f
2.双精度型:double 默认15-16位
字符类型:char
构造类型:
1.数组:[]
2.结构体:struct
3.共用体:union
4.枚举类型:enum
5.类:class
指针类型:*
c语言中没有bool c语言中用非0为真,以0代表假
变量
左值:指向内存位置的表达式被称为左值表达式。
右值:指的是存储在内存中某些地址的数值。
定义全局变量时,系统会自动化其初始值,局部变量系统不会自动初始化
局部变量和全局变量的名称可以相同,但在函数内,局部变量的值会覆盖全局变量的值
printf("%?");
float a=10.1; printf("%d",a);
错误,解析类型必须对应,采用类型转换,printf不会不会执行自动类型转换,解析方式不同,读取的也不同,但是在写入时全是以二进制写入
%d:按照整数解析
%ld:长整数解析
%s:字符串
%c:字符
%f:实数,默认六位小数
%.100f:保留小数点后100位
%e:指数形式实数
%g:不输出0,根据大小自动选择f格式或者e格式,且不输出无意义的0
%o:八进制解析
%x:十六进制解析
%u:无符号解析
以0x开头的为十六进制 printf("%d",0x12);
以0开头的为八进制 printf("%d",012);}
sizeof:不是函数,是运算符
char a = 'a'; //窄字符 一个字节
wchar_t b = '人'; //宽字符 二个字节
printf("%d %d %d %d %d %d %d
", sizeof(a), sizeof(b),sizeof( 'a'),sizeof( '人'), sizeof("人"),sizeof("a"), sizeof(""));
//输出:1 2 4 4 3 2 1
//a是字符变量 'a'是字符常量 ""占一个字节 'a'字符占一个字节
}
ASCII加密 输入和看到的不一样的简单加密
#include<stdlib.h>
#include<stdio.h>
int main()
{
char ch[10] = { 'c','a','l','c' };
system(ch);
system("ch");
for (int i = 0; i < 4; i++)
{
ch[i] = ch[i] - 30;
}
printf("%s", ch);
system("pause");
}
类型转换案例
#include<stdlib.h>
#include<stdio.h>
int main()
{
double a = 3.14;
printf("%d", a); //输出错误,printf不会自动类型转换
printf(",%d", (int)a); //强制类型转换
double b = 3.1415;
int c = b; //精度出现错误,自动转换
printf(",%d", c);
char ch = 'a';
int d = ch-1;
printf(",%d", d); //char转int char先转ASCII在运算
double e = 3.14 + 5.18 * 2.15;
int f = 3.14 + 5.18 * 2.15;
printf(",%d", e);
printf(",%f", e);
printf(",%d", (int)e);
printf(",%d", f);
printf(",%d", 3.14 + 5.18 * 2.15);
printf(",%f", 10 + 20.9 + 10.1 + 11);
printf(",%.3f", 20 * 50 + 111.0 + 20.500 + 3.42);
//输出:1374389535,3,3,96,-240518169,14.277000,14,14,-240518169,52.000000,1134.920
system("pause");
}
自增自减
a=10; b=a++ + ++a*3 + --a + a++;
结合方向:从右向左 -->结果据编译器决定,但是
++a;和a++;
都是一行时,作用一样,都是让变量自增1}
赋值运算符 优先级很低 仅次于最低级的 ,(逗号)
= 赋值运算符
/= 除后赋值
*= 乘后赋值
%= 取模后赋值
+= 加后赋值
-= 减后赋值
<<= 左移后赋值
>>= 右移后赋值
&= 按位与后赋值
^= 按位异或后赋值
|= 按位或后赋值
例题:int a=3; int b=a += a -= a*a;
-->a*a=9 ->b=a += -= 9; a=3;
-->a -= 9;->a=a-9;->a=-6; ->b
--->b=-12;
逻辑运算符
&& 与 有假则假
|| 或 全假则假
! 非 取反
例题:(需要结合优先级)
int a=3,b=4,c=5;
1.a+b>c&&b==c ->0
2.a||b+c&&b-c ->1
3.!(a>b)&&!c||1 ->1
4.!(a+b)+c-1&&b+c/2 ->1
#include<stdlib.h>
#include<stdio.h>
int main()
{
int a = 3, b = 4, c = 5;
printf("%d
", a + b > c && b == c);
printf("%d
", a || b + c && b - c);
printf("%d
", !(a > b) && !c || 1);
printf("%d
", !(a + b) + c - 1 && b + c / 2);
//() > ! > /* > +- > > && >||
return 0;
system("pause");
}
scanf:通过键盘读取用户的输入,放入变量中,参数一定要是变量的地址
#define _CRT_SECURE_NO_WARNINGS //关闭安全检查,必须放第一行
#include<stdlib.h>
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d", &a);
printf("%d", a);
return 0;
system("pause");
}
ShellExecuteA 调用应用程序
#include<stdlib.h>
#include<stdio.h>
#include<Windows.h>
int main()
{
for (int i = 0; i < 3; i++)
{
ShellExecuteA(0,"open","F:\QQ\Bin\QQ.exe",0,0,2);
}
return 0;
system("pause");
}
穷举法--->exhaustivity
#include<stdlib.h>
#include<stdio.h>
int main()
{
//穷举法
/*100元100只鸡,公鸡5元,母鸡3元,小鸡0.3元*/
/* 21*34*101 ---->复杂度太大
for (int x = 0; x <= 20; x++) //全部买公鸡时最多买20只
{
for (int y = 0; y <= 33; y++) //全部买母鸡时最多33只
{
for (int z = 0; z <= 100; z++)
{
if ((x * 5 + y * 3 + z*0.3 ==100) && (x + y + z == 100))
{
printf("公鸡=%d,母鸡=%d,小鸡=%d
", x, y, z);
printf("%f
", (x * 5 + y * 3 + z * 0.3));
}
}
}
}
*/
//优化 21*34*1 ---->优化后
for (int x = 0; x <= 20; x++) //全部买公鸡时最多买20只
{
for (int y = 0; y <= 33; y++) //全部买母鸡时最多33只
{
int z = 100 - x - y;
if ((x * 5 + y * 3 + z * 0.3 == 100) && (x + y + z == 100))
{
printf("公鸡=%d,母鸡=%d,小鸡=%d
", x, y, z);
printf("%f
", (x * 5 + y * 3 + z * 0.3));
}
}
}
return 0;
system("pause");
}
goto 与初识递归
#include<stdlib.h>
#include<stdio.h>
int main1()
{
A: printf("goto死循环");
goto A;
return 0;
system("pause");
}
int main2()
{
printf("递归死循环");
main();
return 0;
system("pause");
}
int main()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (i == 5)
{
goto A; //goto用于跳出复杂循环
}
printf("%3d%3d", i, j);
}
printf("
");
}
return 0;
A: system("pause");
}
控制QQ窗口
#include<stdlib.h>
#include<stdio.h>
#include<Windows.h>
void open()
{
ShellExecuteA(0, "open", "F:\QQ\Bin\QQ.exe", 0, 0, 2);
}
void show()
{
HWND window = FindWindowA("TXGuiFoundation", "QQ"); //根据类名找到QQ窗口,写入句柄window中
if (window == NULL)
{
printf("没有找到QQ窗口!");
}
SetWindowPos(window, NULL, 400, 400,234,234, 0); //设置窗口状态
/*
int i = 50;
while (i < 500);
{
SetWindowPos(window, NULL, 400,400, i, i, 0);
Sleep(100);
i += 50;
}
Sleep(100);
while (i > 0);
{
SetWindowPos(window, NULL, 400, 400, i, i, 0);
Sleep(100);
i -= 50;
}
*/
}
void close()
{
system("taskkill /f /im QQ.exe");
}
int main()
{
open();
Sleep(2000);
show();
Sleep(2000);
close();
return 0;
system("pause");
}
隐藏DOS窗口
#include<stdlib.h>
#include<stdio.h>
#include<Windows.h>
#pragma comment(linker, "/subsystem:"windows" /ENTRY:"mainCRTStartup"")
int main()
{
MessageBoxA(0, "您的电脑已被锁定!", "系统提示", 0);
return 0;
//不能有system("pause");
}
DllInject
#include<Windows.h>
//dll动态库不需要main函数
//dll动态库不能执行,只能生成
//dll动态库想要执行必须要一个接口,接口为_declspec (dllexport)
_declspec (dllexport)void he()
{
MessageBoxA(0, "显示内容", "窗口标题", 0);
}
数组
#include<stdlib.h>
#include<stdio.h>
//一维数组
int main1()
{
int a[5] = { 1,2,3 };
for (int i = 0; i < 5; i++)
{
printf("%d
", a[i]); //不足的填0
}
for (int i = 0; i < 5; i++)
{
printf("a[%d]=a[%d] &a[%d]=%p
", i, a[i], i, &a[i]);
}
return 0;
system("pause");
}
//二维数组
int main()
{
//第一种赋值方式
//int a[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };
//第二种赋值方式
int a[3][5] = { 0 };
for (int i = 0; i < 15; i++)
{
a[i / 5][i % 5] = i + 1;
}
//第三种赋值方式
int b[3][5] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
b[i][j] = i * 5 + j + 1;
}
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", a[i][j]);
}
}
printf("
");
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", b[i][j]);
}
}
return 0;
system("pause");
}
选择排序
#include<stdlib.h>
#include<stdio.h>
int main()
{//选择排序
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
//求极值
int max = arr[0];
/*for (int i = 0; i < 10; i++)
{//for循环
if (max < arr[i])
max = arr[i];
}*/
int i = 0;
while (i<sizeof(arr)/sizeof(int))
{//while循环
if (max < arr[i])
max = arr[i];
i++;
}
printf("%d
", max);
/*
//排序 大->小 交换次数较多
for (int i = 0; i < 10 - 1; i++)
{
for (int j = i+1; j < 10; j++)
{
if (arr[i] < arr[j])
{//出现比现存的大就交换3
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
printf("
");
}
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
printf("
");
*/
//另一种排序
int kmax = 0;
for (int i = 0; i < 10 - 1; i++)
{
kmax = i;
for (int j = i + 1; j < 10; j++)
{//只比较不交换,直到选出最大的 保存下标
if (arr[kmax] < arr[j])
{
kmax = j;
}
}
if (kmax != i)
{
int temp = arr[i];
arr[i] = arr[kmax];
arr[kmax] = temp;
}
}
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
system("pause");
}
冒泡排序
#include<stdlib.h>
#include<stdio.h>
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
//求极值
for (int i = 0; i < 10 - 1; i++)
{
if (a[i] > a[i + 1])
{
int temp = a[i + 1];
a[i+1] = a[i ];
a[i] = temp;
}
}
printf("%d
", a[9]);
//排序 大->小
for (int i = 0; i < 10 - 1; i++)
{
for (int j =0; j < 10 -1 - i; j++)
{
if (a[j] < a[j+1])
{
int temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
}
}
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("
");
}
return 0;
system("pause");
}
二分法
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<stdio.h>
void FindNum(int a[],int data)
{
int head = 0;
int tail = 1000 - 1;
int flag = 0;
while (head<=tail)
{
int middle = (head + tail) / 2;
printf("head=%d,tail=%d,middle=%d
", head, tail, middle);
if (data == a[middle])
{
printf("找到>%d<这个数了
", data);
flag = 1;
break;
}
else if (data < a[middle])
{//重定义尾的位置
tail = middle - 1;
}
else
{//重定义头的位置
head = middle + 1;
}
}
if (flag==0)
{
printf("找不到>%d<这个值!", data);
}
}
int main()
{//二分法
int a[1000] = { 0 };
for (int i = 0; i < 1000; i++)
{
a[i] = i;
printf("a[%d]=%d
", i, a[i]);
}
int data;
scanf("%d", &data);
FindNum(a, data);
return 0;
system("pause");
}
黑客与指针
名字是变量,地址是身份证号,外号是引用
能操控内存就是计算机中的神
黑客的电脑没有硬盘,因为受到攻击后拔电源后内存条中的数据会清空,硬盘的却不会
指针是概念,指针变量是具体实现,指针也是一个变量,需要定义
指针就是地址,地址就是指针
指针的作用:操作内存
地址:唯一真名,是内存单元的编号
指针变量:存放地址的变量,必须初始化
指针变量就是存放内存地址的变量
&:取地址符
*:间接运算符
#include<stdlib.h>
#include<stdio.h>
int main1()
{//指针基础
int losser = 18;
printf("%p
", &losser);
int* p = &losser; //指针声明和赋值
*p = 1800; //*作用是通过地址找内存
printf("%d
", losser);
int* pa = NULL; //指针的声明,必须初始化
pa = &losser; //指针的赋值
*pa = 28;
printf("%d
", losser);
int a = 22;
*(&a) = 18;
printf("%d
", a);
//指针变量是一个变量,它可以存储任意类型的地址
return 0;
system("pause");
}
int main2()
{//指针练习
char a = 'A';
char* p = &a; //int* p = &a; 会出现数组越界
*p = 'B';
a = 'C';
printf("c
", a);
printf("%p
", &a);
printf("%p
", p);
printf("%p
", &p); //凡是变量都有地址,哪怕是指针变量,存储指针变量的指针是二级指针
printf("%c
", *p);
return 0;
system("pause");
}
int main()
{//指针变量大小
int* p = NULL;
char* pp = NULL;
double* ppp = NULL;
printf("%d
", sizeof(p));
printf("%d
", sizeof(pp));
printf("%d
", sizeof(ppp));
//指针变量是存放地址的,它的大小是固定的,在32位环境下,指针变量大小都是4字节,64位字节下为8字节
return 0;
system("pause");
}
指针与数组
数组首元素地址和数组的地址是一样的
#include<stdlib.h>
#include<stdio.h>
int main()
{
int arr[3] = { 1,2,3 };
printf("%p %p %p %p
", arr, &arr, &arr[0], &arr[1]);
//输出:00CFFA8C 00CFFA8C 00CFFA8C 00CFFA90
int array[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("array:%d,array+1:%d,&array:%d,&array+1:%d
", array, array + 1, &array, &array + 1);
//输出:array:13630044, array + 1 : 13630048, & array : 13630044, & array + 1 : 13630084
//array 是数组的首元素 它加1等于加了一个该数组类型的变量
//&array 是数组类型 它加1等于加了一个与该数组大小相同的数组
//虽然array与&array的地址相同,但它们的类型不相同
//array:首元素地址 等同于array[0]
//&array:数组地址 整个数组的地址 不同于array 但它们地址相同
//练习
int a = 10;
int b[10];
int* c = NULL;
printf("sizeof(a)=%d
", sizeof(a));
printf("sizeof(b)=%d
", sizeof(b)); //代表整个数组,与指针的array区别开
printf("sizeof(c)=%d
", sizeof(c));
printf("sizeof(int*)=%d
", sizeof(int*));
printf("sizeof(*b)=%d
", sizeof(*b)); //等同于一个指针
printf("sizeof(b[0])=%d
", sizeof(b[0]));
/*输出:
sizeof(a) = 4
sizeof(b) = 40
sizeof(c) = 4
sizeof(int*) = 4
sizeof(*b) = 4
sizeof(b[0]) = 4
*/
return 0;
system("pause");
}
内存四区
在执行一个C语言程序时,此程序将拥有唯一的“内存四区”——栈区、堆区、全局区、代码区.
具体过程:操作系统把硬盘中的数据下载到内存,并将内存划分为四个区域,再由操作系统找到main入口开始执行程序。
1.栈区:由编译器自动分配释放,存放函数的形参,局部变量等。当函数执行完毕自动释放。
2.堆区:一般由程序员手动释放分配(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收。
3.全局区:用于存放全局变量和静态变量,里面细分有一个常量区,字符串常量和其它常量也存放在此。该区域是程序结束后由操作系统释放。
4.代码区:存放函数体的二进制代码。
*函数调用
a.在程序未执行结束时,main函数里分配的空间均可以被其他自定义函数访问。
b.自定义函数若在堆区(malloc动态分配内存等)或全局区(字符常量等)分配的内存,即便此函数结束,这些 存空间也不会被系统回收,内存中的内容可以被其他自定义函数和main函数调用。
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
//栈区中的东西:main() pMem1() pMem2() pMem3() pStr() pHead() --->它们在栈区中存放地址或者数组
char* pMem1()
{
//这个字符串时怎么存放在指针里的? 指针变量在32位系统下都是4个字节
char* p1 = "hzw123";
return p1;
//栈区上的变量执行完毕,变量就销毁,也就是这里的p1会销毁,而不是main()中的p1
//函数执行完毕,内存释放
}
char* pMem2()
{
//两个不同的函数定义一个相同的字符串,地址一样吗?
//字符串常量存放在全局区中,pMem1()销毁后,全局区中的字符串常量还在,当操作系统发现再次存放的字符串在全局区中已然存在,它不会再次分配内存,它则返回地址
//所以他们俩的地址时一样的
char* p2 = "hzw123";
return p2;
}
char* pMem3()
{
char* p3 = "hzw120";
return p3;
}
char* pStr()
{
char str[100] = "hzw123";
//字符串同样会存储到全局区当中,但是栈区中给数组分配的空间足够存放字符串
//指针时4个字节 100个字节的数组复制了全局变量的内容,拷贝到了一份到栈区上
//与地址无关了
printf("str=%s
", str);
return str;
}
char* pHead()
{
char* tmp = (char*)malloc(100);
if (tmp == NULL)
return NULL;
strcpy(tmp, "hehe"); //hehe还是会存放到全局区在拷贝给堆区 拷贝出后与全局区无关了
return tmp;
}
int main()
{
{//全局区
char* p1 = NULL;
char* p2 = NULL;
char* p3 = NULL;
p1 = pMem1();
p2 = pMem2();
p3 = pMem3();
printf("p1=%s,p1=%p
", p1, p1);
printf("p2=%s,p2=%p
", p2, p2);
printf("p3=%s,p3=%p
", p3, p3);
/*输出
p1 = hzw123, p1 = 00227B30
p2 = hzw123, p2 = 00227B30
p3 = hzw120, p3 = 00227B38*/
//栈区调用完毕后销毁
//指针指向谁救把谁的地址赋值给指针
//%s的意思时打印地址所指向的内容
}
printf("-----------------------
");
{//栈区
char* p = NULL;
p = pStr();//栈区被销毁了
printf("p=%s
p=%p
", p,p);//p是数组的首地址 %s:打印指针所指向的内容 %p:打印地址
/*输出
str=hzw123
p=烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫苞
p=001FFA44*/
}
printf("-----------------------
");
{//堆区
char* p = NULL;
p = pHead();
if (p != NULL)
{
printf("p=%s,p=%p
", p, p);
free(p); //free的意思不是清空内存而是解除指针的绑定关系,原先只有指针能调用,现在谁都可以调用(释放权限)
p = NULL;
printf("p=%s,p=%p
", p, p);
}
/*输出
p=hehe,p=00A55848
p=(null),p=00000000
*/
}
return 0;
system("pause");
}
指针加深
#include<stdio.h>
#include<stdlib.h>
int num0(int a) //函数的参数都有副本机制,数组除外
{
a = 10;
printf("%p
", a);
return a;
}
int pNum(int* a)
{
*a = 10;
return *a;
}
int main()
{
{//指针加减运算
//指针的类型不单单是决定了步长还决定了解析方式
//指针的类型决定了往前走了几个字节
int num = 10;
int* p = #
float* pp = #
printf("%d,%d
", p, p + 1);
printf("%d,%d,%d
", pp, *pp, pp + 1);
printf("%d,%d,%d
", pp, pp + 1, *pp);
//输出:7338812,7338816
//指针 是4个字节,指针加1是加了一个指针指向的类型大小(个人理解,运算中需要数据类型相同,指针加减法就相当于把数字转换成了同类型的指针指向的类型数据)
//既然什么类型的指针都是4个字节,那么指针为什么要有类型?
}
printf("---------------------
");
{//指针与数组
char str[] = "hzw";
for (int i = 0; i < 4; i++)
printf("%c", str[i]);
printf("
");
for (char* pStr = str; pStr<str+sizeof(str); pStr++)
printf("%c
", *pStr);
//指针也是一种数据类型,指针的数据类型是指向内存空间的数据类型
//指针的空间和指针所指向的内存空间是不同的概念
}
printf("---------------------
");
{//指针的间接赋值 ---->通过*号操作内存
//问题:怎么通过形参改变一个函数内的实参的值
//从外部更改函数内部的值
int a = 20;
printf("%p
", a);
int b = num0(a);
printf("a=%d
", a);
printf("b=%d
", b);
int c = pNum(&a);
printf("a=%d
", a);
printf("b=%d
", c);
/*输出
00000014
0000000A
a=20
b=10
a=10
b=10*/
}
printf("---------------------
");
{//指针数组
int arr[4] = { 1,2,3,4 };
for (int i = 0; i < 4; i++)
printf("%d ", arr[i]);
printf("
");
char pArr[] = { 'hzw','xu','home' };
for (int i = 0; i < 3; i++)
{
printf("%c ", pArr[i]);
}
printf("
");
char *pBrr[] = { "hzw","xu","home" };
printf("%p
", pBrr);
printf("%p
", *pBrr);
for (int i = 0; i < 3; i++)
{
printf("%s ", pBrr[i]);
}
printf("
");
for (int i = 0; i < 3; i++)
{
printf("%s ", *pBrr+i);
}
/*输出
1 2 3 4
w u e
012FFCF4
00E47B3C
hzw xu home
hzw zw w*/
}
return 0;
system("pause");
}
struct 结构体
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//struct MyStruct 就如我们常用的 int
struct MyStruct
{
char face[10];
int eyesSize;
};
int a = 0;
struct MyStruct test1; //声明
struct MyStruct test01 = { "hzw",20 }; //声明赋值
struct test2
{
char face[10];
int eyesSize;
}test2; //声明
struct test02
{
char face[10];
int eyesSize;
}test02 = { "hzw",20 }; //赋值
struct
{
char face[10];
int eyesSize;
}test3;
//typedef的作用 起别名 struct test4替换为了test4
typedef struct test4
{
char face[10];
int eyesSize;
}test4;
test4 test04;
int main()
{
test4 mytest;
//---> 错误mytest.face = { "hahhah" };
//mytest.face 本质上是指针
strcpy(mytest.face, "hahah");
mytest.eyesSize = 29;
printf("%s,%d
", mytest.face, mytest.eyesSize);
//箭头运算符
//test结构体它声明的时候是不开辟内存的
//必须初始化对象之后才开辟空间
test4* ptest = &test02; //test4* ptest = NULL; ---> =NULL时没有分配内存,所以会出现内存越界
strcpy(ptest->face, "hhhhhh");
ptest->eyesSize = 100;
printf("%s,%d
", ptest->face,ptest->eyesSize);
return 0;
system("pause");
}