我有一项任务是将一些输入复制到链表中,但是当我尝试使用strncpy
复制此输入时,它不起作用并且出现错误
Exception thrown at 0x0F4C0E15 (ucrtbased.dll) in
ProjectA.exe: 0xC0000005: Access violation writing location 0xCDCDCDCD.
代码:
typedef struct Frame
{
char* name;
unsigned int duration;
char* path;
} Frame;
typedef struct FrameNode
{
Frame* frame;
struct FrameNode* next;
} FrameNode;
FrameNode* createframe(char name[], char path[], int duration)
{
Frame* list = (Frame*)malloc(sizeof(Frame));
strncpy((list->name), name, STR_LEN);
list->duration = duration;
strncpy(list->path, path, STR_LEN);
FrameNode* frame = list;
frame->next = NULL;
return list;
}
答案 0 :(得分:2)
在目标中复制字符串之前,需要使用malloc
分配空间。第一个malloc仅为Frame
分配空间,而不为其内部char *
分配空间。
您的createframe
中的代码应为:
Frame* list = malloc(sizeof(Frame));
list->name = malloc(STR_LEN);
strncpy((list->name), name, STR_LEN);
list->duration = duration;
list->path= malloc(STR_LEN);
strncpy(list->path, path, STR_LEN);
//FrameNode* frame = list; // <- nope. FrameNode* should point to a FrameNode not a Frame
FrameNode* frame = malloc(sizeof(FrameNode));
frame->frame = list;
frame->next = NULL;
return frame;
在使用动态分配的变量之前检查malloc
是否成功也将是一件好事,
Frame *list = malloc(sizeof(Frame));
if(list==NULL){
perror("problem allocating frame");
return NULL;
}
list->name = malloc(STR_LEN);
if(list->name==NULL){
free(list);//free the already allocated memory
perror("error message");
return NULL;
}
strncpy((list->name), name, STR_LEN);
...
return frame;
}
当createframe
返回时,您应该检查它是否返回了NULL
,如果返回了NULL
,则通常通过释放分配的内存并终止程序来处理错误。 / p>
答案 1 :(得分:2)
在malloc()
之后,list->name
是未初始化的指针。您需要为字符串分配足够的空间,然后复制到该空间。与path
类似。不要忘记在字符串末尾留空字节。您没有为FrameNode
分配空间;您也不返回它。
FrameNode *createframe(char name[], char path[], int duration)
{
Frame *list = (Frame*)malloc(sizeof(*list));
size_t name_len = strlen(name) + 1;
char *name_cpy = malloc(name_len);
size_t path_len = strlen(path) + 1;
char *path_cpy = malloc(path_len);
FrameNode *frame = malloc(sizeof(*frame));
if (list == NULL || name_cpy == NULL || path_cpy == NULL || frame == NULL)
{
free(name_cpy);
free(path_cpy);
free(frame);
free(list);
return NULL;
}
list->duration = duration;
memmove(path_cpy, path, path_len);
memmove(name_cpy, name, name_len);
list->name = name_cpy;
list->path = path_cpy;
frame->frame = list;
frame->next = NULL;
return frame;
}
其中有很多修复程序。
Frame
和FrameNode
分配空间。NULL
,可以安全地将其传递给free()
。memmove()
(或memcpy()
)来复制数据。sizeof(*variable)
表示法代替sizeof(VariableType)
。FrameNode *
而不是Frame *
。strncpy()
,因为这不能保证复制的字符串以null结尾,这会导致其他地方出现问题。STR_LEN
-尚不清楚它具有什么价值。如果您对name
和path
的大小确实有固定的上限,那么最好使用以下结构:
typedef struct Frame
{
unsigned int duration;
char name[STR_LEN + 1];
char path[STR_LEN + 1];
} Frame;
STR_LEN
的字符串加上空终止符。STR_LEN
的值如何,都将字符数组放在结构的末尾以最大程度地减少填充。strncpy()
并确保设置list->name[STR_LEN] = '\0';
和list->path[STR_LEN] = '\0';
-这就是为什么成员定义中有+ 1
的原因。此变体将分配的数量从4减少到2。您甚至可以在next
结构中包含Frame
指针,并完全取消FrameNode
结构-再次减少所需的内存管理量,从而简化了代码。也可能有充分的理由将FrameNode
与Frame
分开,但这在问题中的信息中并不清楚,也没有必要。这就是您要考虑的事情了。
答案 2 :(得分:0)
对于初学者来说,该函数应声明为
FrameNode * createframe( const char name[], const char path[], int duration );
因为函数中的name
和path
均未更改。
您没有为list->name
,list->path
和frame
分配内存。
此外,该函数返回类型为frame
的{{1}}而不是类型FrameNode *
的{{1}}。
当动态分配字符数组时(如您的情况),结构list
的数据成员Frame *
和STR_LEN
时,命名常量name
毫无意义。
首先,您应该为path
类型的对象动态分配内存。
然后,您应该为Frame
类型的对象及其数据成员FrameNode
和Frame
分配内存。
因此,函数定义可以如下所示。
name
如果您确实需要限制动态分配的字符串的长度,那么这些语句
path
和
FrameNode * createframe( const char name[], const char path[], int duration )
{
FrameNode *frame = malloc( sizeof( FrameNode ) );
if ( frame != NULL )
{
char *name_data = NULL;
char *path_data = NULL;
size_t n = strlen( name );
name_data = malloc( n + 1 );
if ( name_data != NULL ) strcpy( name_data, name );
if ( name_data != NULL )
{
n = strlen( path );
path_data = malloc( n + 1 );
if ( path_data != NULL ) strcpy( path_data, path );
}
Frame *list = NULL;
if ( name_data != NULL && path_data != NULL )
{
list = malloc( sizeof( Frame ) );
if ( list != NULL )
{
list->name = name_data;
list->duration = duration;
list->path = path_data;
}
}
if ( list == NULL )
{
free( name_data );
free( path_data );
free( frame );
}
else
{
frame->frame = list;
frame->next = NULL;
}
}
return frame;
}
应替换为
size_t n = strlen( name );
name_data = malloc( n + 1 );
if ( name_data != NULL ) strcpy( name_data, name );
和
n = strlen( path );
path_data = malloc( n + 1 );
if ( path_data != NULL ) strcpy( path_data, path );
否则,相对于存储的数据将存在不一致:某些节点将存储字符串,而另一些节点将包含非字符串。