之前说过一个问题,函数传参是副本机制。但是数组是一个例外,用数组做参数,传递的是一个地址。也就是说,数组这个东西是直逼内存地址的。
数组作为函数参数,会退化为一个指针,一级指针作为函数形式参数传递地址
小程序:程序执行20秒以后,实现即时退出,通过控制台来展示信息
int main()
{
int i = 0;
while (1)
{
i++;
char str[50];
if (i > 20)
{
exit(0);
}
//黑窗口的信息是通过system来进行输出的,要格式化好了在输出
sprintf(str, "title 程序运行%d秒", i);
system(str);//往控制台输出信息
Sleep(1000);
}
system("pause");
return 0;
}
下面我们来说一下什么是空指针,什么是野指针。
没有初始化的指针就是野指针,指向了内存里面的垃圾数据。随便指,乱指。
空指针就是让指针指向NULL这个地方,也就是000000
注意,空指针是不可以取值的,因为它指向的是操作系统大哥所用的数据。
system的处理情况可以直接传入一个字符指针,然后它会遍历里面的值,进行打印输出。
char str[20] = "notepad";
char *p = str;
system(p);
上面这种就会打开记事本
char str1[20] = "notepad";
char str2[20] = "tasklist";
void ChangePoint(char** str)
{
//用二级指针保存指针的地址
*str = str1;
}
int main()
{
char *p = str2;
ChangePoint(&p);//函数有副本机制
system(p);//这里指针就被改变了指向
system("pause");
return 0;
}
下面来说一下字符串的封装问题。
我们需要自己写一个库,可以对字符串查找,删除,添加,修改等操作。
我们需要建立一个头文件,来声明我们的函数,还有我们需要一个.c文件来来实现里面声明的函数与定义的库。最后我们的主体文件要包含我们的头文件。
字符串封装单独用一个文件来说。
下面来说一下,什么是结构体。
结构体就是多种数据在一起的一个组合。
我们把结构体看成一种数据的集合。
比如一个字符串,用结构体来表示,可以存放它的地址,存放它的长度。
结构体分配的内存空间都是独立的。它里面的数据也是你一片连续的内存空间。里面的每个数据存储都是独立的
结构体只又有在创建变量的时候才分配内存。
注意,结构体字符串的复制,只有用sprintf或者strcpy函数复制进去,不能直接进行赋值
结构体变量名与成员名完全可以重名。
无名结构体。
无名结构体也可以叫贵宾结构体,它无法在外部创建一个变量进行访问成员变量,它只能在定义结构体时就定义好变量。相当于是限量发行结构体。
struct
{
char name[20];
int height;
}people1 = { "蒲向鑫", 178 }, people2 = {"唐甜",177};
int main()
{
//上面就是初始化了连个匿名结构体
printf("%s,%d\n", people1.name, people2.height);
system("pause");
return 0;
}
下面说一下,结构体变量用大括号来赋值,只有在创建并且初始化的时候才可以。
可以将一个结构体变量赋值给另外一个结构体变量,前提是必须是同一个结构体类型。
下面来简单说一下结构体嵌套的使用。
struct Mystruct
{
char str[20];
int num;
};
struct Youstruct
{
int data;
char you[20];
struct Mystruct my1;//嵌套一个结构体类型。
};
int main()
{
//我们知道嵌套结构体是通过点去访问的,那么嵌套就是双点
struct Youstruct you1;
sprintf(you1.my1.str, "love");
you1.my1.num = 520;
printf("%s,%d,\n", you1.my1.str, you1.my1.num);
system("pause");
return 0;
}
两个相同同结构体之间字符串是不可以单独直接进行赋值的。
下面来说一下,结构体内部嵌套结构体的使用。
struct FatherPeo
{
int data;
char name[20];
struct Beijing
{
char str[20];
int num;
};
};
int main()
{
//上面就是结构体内嵌结构体
struct FatherPeo t1;
t1.data = 80;
t1.num = 20;
sprintf(t1.name, "pxx");
sprintf(t1.str, "zhangsan");
printf("%d %d %s %s\n", t1.data, t1.num, t1.name, t1.str);
system("pause");
return 0;
}
结构一体内部嵌套一个结构你,内部的结构体成员就像普通成员一样访问就可以了。
注意嵌套一个结构体与嵌套一个结构体变量是不一样。
嵌套一个结构体变量,我们需要用双点去访问。
下面来说一下,结构体数组的问题。
结构体数组无非就是,数组里面的每一个元素都是一个结构体。
初始化按照元素个数进行初始化就可以了。
struct People
{
char name[20];
int height;
};
int main()
{
struct People p1[2] = { { "pxx", 178 }, { "tt", 177 } };
printf("%x %x %x\n", p1, &p1[0], &p1[1]);//p1与p1[0]的地址都是一样的
//说明结构体数组中的成员在内存里面是一片连续的存储空间
printf("%s,%s\n", p1[0].name, p1[1].name);
system("pause");
return 0;
}
下面来说一下,指针与结构体
结构体的指针是保存结构体变量的地址的。然后可以通过->的形式去访问里面的数据。
结构体指针有两种方法来访问结构体中的数据
第一种->成员名
第二种*p.成员名
下面来做一个小例子,用结构体指针做函数参数,改变结构体成员里面的值
struct People
{
char name[20];
int height;
};
void ChangeStructData(struct People *p)
{
//用结构体指针作为函数参数,指针保存的是结构体变量的地址,直逼内存地址,然后修改数据
sprintf(p->name, "tt");
p->height = 120;
}
int main()
{
struct People p1;
sprintf(p1.name, "pxx");
p1.height = 170;
printf("%s %d\n", p1.name, p1.height);//pxx 170
ChangeStructData(&p1);
printf("%s %d\n", p1.name, p1.height);//tt 120
system("pause");
return 0;
}
这里我们必须注意一下。内存必须保证有足够的带大小来存放数据,不管是结构体数据还是数组数据,都要保证有足够的大小来存放这样的数据。
这里来说一下,结构体大小的问题
1.结构体的总大小必须是最宽基本类型(char int double float)成员的整数倍。
2.内存要进行字节对齐,字节不对齐,内存地址计算就不规律了,内存寻址时间就会加大。
3.肯定是大于等于所有成员大小和
4.结构体成员的偏移量必须是当前成员的整数倍
下面来说一下共用体。
union
大致结构体的很多类似
来说一下,它的内存空间大小。
它里面最大成员空间内存是多大,它就是多大。
这里我来说两个问题:
第一:共用体在任何时候只有一个成员变量存在。那么是什么呢,就是在内存里面,最先赋值的成员变量保留,其他打印出来全都是垃圾数据
第二:共用体的内存==最长成员的内存大小,如果是数组,就按照数组的内存大小来为其分配内存。当然,为了寻址,可能要进行字节填充。注意,必须可以被最小字节整除。
共用体什么值会存在于内存当中,就是先赋值的值会存在与内存当中。后面赋的值打出来就是乱码