使用字符串复制到链接列表不起作用

时间:2019-06-16 12:38:58

标签: c string memory-management linked-list singly-linked-list

我有一项任务是将一些输入复制到链表中,但是当我尝试使用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;
}

3 个答案:

答案 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>


You should not cast the result of malloc

答案 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;
}

其中有很多修复程序。

  • 它为FrameFrameNode分配空间。
  • 代码检查分配失败。
  • 它尝试在检查故障之前分配所有内存,从而简化了错误处理。只有一个错误返回。如果第一次分配失败,那么剩下的机会也将是,将变量初始化为NULL,可以安全地将其传递给free()
  • 它计算字符串的长度。
  • 它为字符串及其空终止符分配空间。
  • 由于知道字符串的长度,因此可以使用memmove()(或memcpy())来复制数据。
  • 它使用sizeof(*variable)表示法代替sizeof(VariableType)
  • 它返回FrameNode *而不是Frame *
  • 它避免使用strncpy(),因为这不能保证复制的字符串以null结尾,这会导致其他地方出现问题。
  • 它没有注意STR_LEN -尚不清楚它具有什么价值。

结构的替代设计

如果您对namepath的大小确实有固定的上限,那么最好使用以下结构:

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的原因。
  • li>

此变体将分配的数量从4减少到2。您甚至可以在next结构中包含Frame指针,并完全取消FrameNode结构-再次减少所需的内存管理量,从而简化了代码。也可能有充分的理由将FrameNodeFrame分开,但这在问题中的信息中并不清楚,也没有必要。这就是您要考虑的事情了。

答案 2 :(得分:0)

对于初学者来说,该函数应声明为

FrameNode * createframe( const char name[], const char path[], int duration );

因为函数中的namepath均未更改。

您没有为list->namelist->pathframe分配内存。

此外,该函数返回类型为frame的{​​{1}}而不是类型FrameNode *的{​​{1}}。

当动态分配字符数组时(如您的情况),结构list的数据成员Frame *STR_LEN时,命名常量name毫无意义。

首先,您应该为path类型的对象动态分配内存。

然后,您应该为Frame类型的对象及其数据成员FrameNodeFrame分配内存。

因此,函数定义可以如下所示。

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 );   

否则,相对于存储的数据将存在不一致:某些节点将存储字符串,而另一些节点将包含非字符串。