C 操纵数组会导致segfault?
我正在编写一个C应用程序,它涉及到将一个文本文件(以一种称为VSM的格式,因此使用下面的名称)解析为一个树结构。格式的设计者称之为标记树。每个节点都有一些键值对(或属性)和子节点 以下是所讨论的结构和功能: vsm.h:C 操纵数组会导致segfault?,c,arrays,segmentation-fault,C,Arrays,Segmentation Fault,我正在编写一个C应用程序,它涉及到将一个文本文件(以一种称为VSM的格式,因此使用下面的名称)解析为一个树结构。格式的设计者称之为标记树。每个节点都有一些键值对(或属性)和子节点 以下是所讨论的结构和功能: vsm.h: struct vsm_node { int numchildren; struct vsm_attribute *attrs [36]; struct vsm_node *children[8]; };
struct vsm_node {
int numchildren;
struct vsm_attribute *attrs [36];
struct vsm_node *children[8];
};
void vsm_addchild(struct vsm_node *node, struct vsm_node *child);
vsm.c:
#include "vsm.h"
void vsm_addchild(struct vsm_node *node, struct vsm_node *child)
{
node->children[node->numchildren] = child;
++(node->numchildren);
}
为什么我调用vsm\u addchild
时会产生一个segfault
抱歉,如果这是一个愚蠢的问题,但我真的很烂的普通C。特别是如果它与指针和内存管理有关
编辑以包含拨打电话的代码:
#include <stdio.h>
#include "vsm.h"
void vsm_parse(struct vsm_node *tree, FILE *fp, char *name)
{
struct vsm_node *this = tree;
int ch;
while ((ch = fgetc(fp)) != 0) {
...
else if (ch == '{') {
struct vsm_node *node;
vsm_initnode(node);
vsm_addchild(this, node);
this = node;
...
...
gdb输出:
Program received signal SIGSEGV, Segmentation fault.
vsm_addchild (node=0x28, child=0x7541612d <msvcrt!_atodbl_l+2294>) at vsm.c:62
62 node->children[node->numchildren] = child;
程序接收信号SIGSEGV,分段故障。
vsm.c:62处的vsm_addchild(节点=0x28,子节点=0x7541612d)
62节点->子节点[节点->子节点]=子节点;
以下是此代码可能出现故障的原因:
查看粘贴的调用代码 调用代码不分配节点;它是一个未初始化的指针,这意味着它指向内存中的随机位置。 由于命名错误,误读了代码。传递的子对象是未初始化的指针,但在演示的代码中不会出现segfault,因为它从未被解除引用
第一次输入
{
时,它应该可以正常工作。第二次它应该segfault,因为this=node
将this
设置为未初始化的指针。以下是此代码可能segfault的原因:
查看粘贴的调用代码 调用代码不分配节点;它是未初始化的指针,这意味着它指向内存中的随机位置。 由于命名错误,误读了该代码。传递的子项是未初始化的指针,但这不会在演示的代码中显示segfault,因为它从未被取消引用
第一次
{
输入后,它应该可以正常工作。第二次它应该会出错,因为this=node
将this
设置为未初始化的指针。您错误地初始化了节点指针。这意味着您传递的node
变量无效,并且随机指向内存,几乎是肯定的只能将其放入进程不拥有的内存中,从而导致分段错误。请改为尝试以下操作:
// Change (1): new return type, parameter removed
struct vsm_node* vsm_initnode()
{
struct vsm_node* node;
node = malloc( sizeof(struct vsm_node)); // Change (2)
// The following lines are unnecessary - change (3)
//node->attrs = malloc(36 * sizeof(struct vsm_attribute *));
// node->children = malloc( 8 * sizeof(struct vsm_node *));
node->numchildren = 0;
int i;
for (i = 0; i < 36; ++i)
node->attrs[i] = NULL; // unnecessary but good practice
for (i = 0; i < 8; ++i)
node->children[i] = NULL;
return node;
}
void vsm_addchild(struct vsm_node *node, struct vsm_node *child)
{
node->children[node->numchildren] = child;
++(node->numchildren);
}
这意味着,当您分配
struct vsm_节点
对象时,无论是通过使用malloc
还是通过简单地声明struct vsm_节点
类型的变量,它都已经有足够的内存用于两个指针数组。分配更多内存不仅是不必要的,而且是浪费的。它还可能导致您的程序无法正常运行ave与仅使用数组并分配额外内存时的情况不同。您错误地初始化了节点指针。这意味着您传递的节点
变量无效,并随机指向内存,几乎可以肯定指向您的进程不拥有的内存,从而导致分段错误出现故障。请尝试以下操作:
// Change (1): new return type, parameter removed
struct vsm_node* vsm_initnode()
{
struct vsm_node* node;
node = malloc( sizeof(struct vsm_node)); // Change (2)
// The following lines are unnecessary - change (3)
//node->attrs = malloc(36 * sizeof(struct vsm_attribute *));
// node->children = malloc( 8 * sizeof(struct vsm_node *));
node->numchildren = 0;
int i;
for (i = 0; i < 36; ++i)
node->attrs[i] = NULL; // unnecessary but good practice
for (i = 0; i < 8; ++i)
node->children[i] = NULL;
return node;
}
void vsm_addchild(struct vsm_node *node, struct vsm_node *child)
{
node->children[node->numchildren] = child;
++(node->numchildren);
}
这意味着,当您分配
struct vsm_节点
对象时,无论是通过使用malloc
还是通过简单地声明struct vsm_节点
类型的变量,它都已经有足够的内存用于两个指针数组。分配更多内存不仅是不必要的,而且是浪费的。它还可能导致您的程序无法正常运行ave与仅使用阵列并分配额外内存的情况不同。您正在为中的节点分配内存
vsm_initnode(struct vsm_node *node)
这里的节点是一个局部变量,当vsm_initnode()时,您为节点所做的分配将丢失完成其执行并返回其调用模块。有点像悬空指针问题。为了保留分配,必须使用双指针或返回内存地址
下面您可以找到这两个(双指针和返回内存地址)实现
void vsm_parse(struct vsm_node *tree, FILE *fp, char *name)
{
struct vsm_node *this = tree;
int ch;
while ((ch = fgetc(fp)) != 0) {
...
else if (ch == '{') {
// Creating a object pointer.
struct vsm_node *node;
/**********************************/
/* Double Pointer Implementation */
/**********************************/
vsm_initnode_double_pointer(&node);
/******************************************/
/* Return Memory Address Implementation */
/******************************************/
node=vsm_initnode_return_address();
vsm_addchild(this, node);
this = node;
...
...
// Double Pointer Implementation
void vsm_initnode_double_pointer(struct vsm_node **node)
{
*node=malloc(sizeof(struct vsm_node *));
// No need to allocate memory for attrs, children because it has been declared as array. You can directly store the memory location values in it.
(*node)->numchildren = 0;
int i;
for (i = 0; i < 36; ++i)
(*node)->attrs[i] = NULL;
for (i = 0; i < 8; ++i)
(*node)->children[i] = NULL;
}
// Return Memory Address Implementation
struct vsm_node * vsm_initnode_return_address()
{
struct vsm_node *temp=malloc(sizeof(struct vsm_node *));
// No need to allocate memory for attrs, children because it has been declared as array. You can directly store the memory location values in it.
temp->numchildren = 0;
int i;
for (i = 0; i < 36; ++i)
temp->attrs[i] = NULL;
for (i = 0; i < 8; ++i)
temp->children[i] = NULL;
return temp
}
void vsm_parse(结构vsm_节点*树,文件*fp,字符*name)
{
结构vsm_节点*此=树;
int-ch;
而((ch=fgetc(fp))!=0){
...
else如果(ch='{'){
//创建对象指针。
结构vsm_节点*节点;
/**********************************/
/*双指针实现*/
/**********************************/
vsm_initnode_双_指针(&node);
/******************************************/
/*返回存储器地址实现*/
/******************************************/
node=vsm_initnode_return_address();
vsm_addchild(此,节点);
这个=节点;
...
...
//双指针实现
void vsm_initnode_双_指针(结构vsm_节点**节点)
{
*node=malloc(sizeof(struct vsm_node*);
//无需为属性、子级分配内存,因为它已声明为数组。您可以直接在其中存储内存位置值。
(*节点)->numchildren=0;
int i;
对于(i=0;i<36;++i)
(*节点)->attrs[i]=NULL;
对于(i=0;i<
void vsm_parse(struct vsm_node *tree, FILE *fp, char *name)
{
struct vsm_node *this = tree;
int ch;
while ((ch = fgetc(fp)) != 0) {
...
else if (ch == '{') {
// Creating a object pointer.
struct vsm_node *node;
/**********************************/
/* Double Pointer Implementation */
/**********************************/
vsm_initnode_double_pointer(&node);
/******************************************/
/* Return Memory Address Implementation */
/******************************************/
node=vsm_initnode_return_address();
vsm_addchild(this, node);
this = node;
...
...
// Double Pointer Implementation
void vsm_initnode_double_pointer(struct vsm_node **node)
{
*node=malloc(sizeof(struct vsm_node *));
// No need to allocate memory for attrs, children because it has been declared as array. You can directly store the memory location values in it.
(*node)->numchildren = 0;
int i;
for (i = 0; i < 36; ++i)
(*node)->attrs[i] = NULL;
for (i = 0; i < 8; ++i)
(*node)->children[i] = NULL;
}
// Return Memory Address Implementation
struct vsm_node * vsm_initnode_return_address()
{
struct vsm_node *temp=malloc(sizeof(struct vsm_node *));
// No need to allocate memory for attrs, children because it has been declared as array. You can directly store the memory location values in it.
temp->numchildren = 0;
int i;
for (i = 0; i < 36; ++i)
temp->attrs[i] = NULL;
for (i = 0; i < 8; ++i)
temp->children[i] = NULL;
return temp
}