一、结构体含有指针成员的申请问题: 首先假设结构体中含有指针成员,那么如果我们用malloc给结构体申请空间的话,有两种情况:①若指针成员是数组,那么申请的空间中包含数组的空间,数组可以直接使用;----------------------------------------------------------------------- ②若指针成员是指针变量,申请的空间中当然也包含这个指针变量《自身》所占的空间,但是当我们操作这个指针变量时【是指我们让*指针=某个数(错误),而不是指让这个指针变量指向某一地址(正确,相当于初始化)】。我们需要给这个指针变量初始化,因为此时的指针变量是个野指针(也就是没有初始化的指针)【(也就是说它指向的地址是一个随机值,此时如果改变它的内容会造成不知道某个地方的改变,有可能是系统某个地方的改变,因此是错误的。《所以没有初始化的指针是不能够使用的》】。当然如果我们没有一块现成的地址供其指向,我们可以用malloc申请一块空间让其指向,以初始化该指针。
struct node{
char data[50];
char *name;
node *left;
node *right;
};
若结构体中含有指针成员,那么创建一个结构体时,要使用malloc申请一块空间,用来存储这个结构体。
node *N = (node *)malloc(sizeof(struct node));
申请一块空间,大小为:sizeof(char)*50 + sizeof(char ) + sizeof(node)*2 , 然后将这块申请的空间的地址赋值给 N。
接下来就存在两种情况:
1、指针成员是数组: 这种情况下,直接对结构体malloc申请空间,这块空间里就给数组申请了一块空间。可以直接使用数组data。
2、指针成员是指针变量: 这种情况下,即使给结构体malloc申请了变量,也要给这个指针变量malloc申请空间(如果要操作指针的话:即操作指针所指向空间的内容)。
原因是因为:当我们给这个结构体申请空间了之后,确实给指针成员name、left、right分配了空间,但这是name、left、right有了他自己的地址( 如name 就是char** ),但他里面存的内容同样是一个地址p(name *), 此时这个p是个野指针(也就是没有初始化的指针),也就是说它的指向是一个随机值,此时如果操作这个指针p(更改指针p所指向地址的内容),是错误的。没有初始化的指针是不能够使用的。
类似于声明一个int类型变量的a: int a=5;
,此时栈空间给a开辟了一块空间,这是a他自己的地址,但是他同时存了一个int 类型的值,值为5。指针也是如此,只有了他自己的地址,但是他的内容是不确定的,是任意的一个存在的地址。
(1)
此时如果我们直接操作name、left、right,如 N->left = NULL;
或 N->left = &node A;
这样就是给 name、left、right 初始化或者赋值,即改变这块地址的内容,也就是说,name、left、right已经有了自己的地址,然后更新了这块地址所存入的内容(还是一个一个地址),此时内容就不是任意的了,而是我们指定的正确的了,然后我们就可以操作这块地址所存的内容(实际上是一个地址)它所指向的内容了。(当然N->left = NULL时,仍是不能操作的,因为他没有指向一块空间,而是一个空指针)。
(2)
此时如果我们操作name、left、right的内容 ,要先对其初始化然后才能使用。如 strcpy(N->name,"no name");
,这样就是不对的,会给一块不确定的地址赋值为"no name",这是个灾难,因为你不知道这块地址的内容的类型是什么,就算是char 类型的,也改变了原来的内容。所以此时我们就要给name、left、right的内容赋一个具体的指向了,我们直接申请一块char类型、node类型的空间,让name、left、right、指向它们,这样name、left、right里面的内容(地址)不就不是任意的了嘛,可以对name、left、right的内容进行操作了,操作的就是新申请的那一块空间。
N->name = (char *)malloc(sizoef(char)*50));
N->left = (node *)malloc(sizoef(node));
N->right = (node *)malloc(sizeof(node));
下面看代码:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string.h>
using namespace std;
struct node{
char data[50];
char *name;
node *left;
node *right;
};
int main()
{
node *N=(node *)malloc(sizeof(struct node)) ;
cout<<"N的地址:";
cout<<N<<endl;
cout<<"此时没有给name、left、right申请新的空间"<<endl;
cout<<"N中data数组的地址: ";
cout<<&(N->data)<<endl;
// cout<<"name的地址:";
// cout<<&(N->name)<<endl;
cout<<"left的地址:";
cout<<N->left<<endl;
cout<<"right的地址:";
cout<<N->right<<endl;
cout<<"此时给name、left、right申请新的空间"<<endl;
N->name = (char *)malloc(sizeof(char)*50);
strcpy(N->name,"no name");
// cout<<"name的地址:"<<endl;
// cout<<&(N->name)<<endl;
N->left = (node *)malloc(sizeof(node));
cout<<"left的地址:";
cout<<N->left<<endl;
N->right = (node *)malloc(sizeof(node));
cout<<"right的地址:";
cout<<N->right<<endl;
return 0;
}
总之,也就是说含有指针变量的结构体,要先对其指针变量进行初始化,如果没有现成的地址让其指向,我们就需要申请一块空间让其指向,即初始化。然后才能使用这个指针,所谓的使用也就是对这个指针所指向地址的内容进行更改。
二、①我们当然可以在程序中间静态声明一个数组,这和在程序中间声明一个int n;
是一样的。同样会在栈空间开辟一块空间,当然这块空间的大小必须是个常量,如int a[10];
。我们使用动态申请空间,如开辟一个数组主要是为了不浪费空间或防止空间不够,
如int *p = (int *)malloc(sizeof(int)*n);
##n是个变量而不是常量, 这样我们就可以根据程序算出来的值来更合理化地开辟空间供我们使用。
②对于结构体(可能还有指针变量成员或者数组成员都是ok的)也是一样,我们当然可以在程序中间静态声明,这会在栈空间开辟一块空。
在程序中间直接 node Node;
当然也是ok的,这和在程序中间声明了一个char类型的数组外加三个没有初始化的指针是一样的。
《在C语言中结构体之间的整体赋值是完全支持的》: 简单结构体(不包含指针成员)直接赋值没有问题。但若结构体中含有指针成员,将会进行浅复制,也就是两个指针指向同一块内存,可能会出现以下问题:①赋值会直接将结构体的指针变量被赋值,赋值之前其所指向的内存单元丢失; ②赋值之后若该指针指向的内存单元被其它指针释放掉,那么继续使用该成员指针的话则又可能导致内存泄漏。
现在我认为动态申请一个数组或者是一个结构体,不是因为数组是在程序运行之前就分配好了的事,并没有那么简单,当然可以在程序运行过程中声明一个数组,或是一个结构体。 之所以我们使用动态申请一个数组或是结构体,有两个方面的原因:一是动态申请数组可以控制数组的大小,而静态数组申请的大小必须是常数。二是动态申请结构体,不会随着函数的结束而被释放掉。
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
if(n){
int a[3];
a[0]=1;a[1]=2;a[2]=3;
for(auto i :a)
cout<<i;
}
return 0;
}
for(int i=0;i<cnt-1;i++){
N=(node *)malloc(sizeof(struct node));
N->left=Delete(S);//此时还没有给指针初始化,对指针进行初始化
N->right=Delete(S);
N->data='*';
N->weight=N->left->weight+N->right->weight;
Insert(S,N);
}