C:使用 realloc() 转储核心

C: Core dumped with realloc()

在开始之前,我应该说我已经看过几篇关于这个主题的帖子(比如 this one,但我仍然遗漏了一些东西。我对 C 很陌生,所以请耐心等待。我正在尝试构造一个将字符串从一个指针位置复制到另一个指针位置的函数。

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void astrncpy(char **base, char *copyme){

    printf("Copying '%s' into a location currently featuring the following string: '%s'\n", copyme,*base);
    printf("The location of our string to be copied (%s) is %d.\n", copyme, &copyme);
    printf("The location of our string to be replaced (%s) is %d.\n", *base, base);

    //Declare string length variable
    int new_len=strlen(copyme);
    printf("Calculating new length for replaced memory allocation (%d).\n",new_len);

    //Reallocate pointer array
    *base=realloc(*base,sizeof(char)*new_len+1);
    printf("Reallocating memory allocation.\n");

    //Copy copyme content to base string location
    strncpy(*base,copyme,new_len);

    printf("The string at location %d is now %s\n", base, *base);

}

void main(){

    //Declare iterator
    int i;

    //Generate strings
    char first_lit[]="Fortran?";
    char second[]="Now that's a name I've not heard in a long time.";

    //Convert first string to array (so we can get at the pointer to the strings pointer)
    char **first; //Declare pointer to pointer array that represents the first string
    first=malloc(strlen(first_lit)*sizeof(char)); //Allocate space for the pointer array
    *first=first_lit; //Assign values to the pointer locations

    //Copy copyme into base
    astrncpy(first,second);
}

当我尝试在 astrncpy() 内重新分配时,核心转储。据我了解,如果指针数组不是 NULL,或者不是 malloc() 的乘积,就会发生这种情况。我觉得我没有通过那个测试。任何有关正在发生的事情的指导将不胜感激。

深入了解我的输入构造的加分项 *base。我花了很多时间进行试验以确定 **base 参数的可接受输入是什么(请注意 astrncpy() 的两个参数都在我正在研究的文本中给出)。但是,我不清楚为什么我不能使用 first_lit 而不是必须构建 first。字符串仍然是一个数组,不是吗?再次感谢您的帮助。

UPDATE:我把它搁置了一段时间去做我实际上得到报酬的工作,但回过头来,我无法动摇声明的想法无需修改以下回复。 (这是因为它们尚未在文本中涵盖。)无论如何,我仍将检查该解决方案,因为它有效并且在多个方面都有帮助。但是,应该注意的是,以下内容也有效:

/*Program demonstrates string manipulation operations*/

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void astrncpy(char **base, char *copyme){

    printf("\nWe are inside the function, astrncpy.\n");
    printf("\nCopying '%s' (*copyme) into a location currently featuring the following string: '%s' (**base)\n", copyme,*base);
    printf("The location of our string to be copied (%s) is %p.\n", copyme, &copyme);
    printf("The location of our string to be replaced (%s) is %p.\n", *base, base);

    //Declare string length variable
    size_t new_len=strlen(copyme);
    printf("Calculating new length for replaced memory allocation (%d).\n",new_len);

    //Reallocate pointer array
    printf("Reallocating memory block associated with base string to be replaced.\n");
    *base=realloc(*base,sizeof(char)*(new_len+1));


    //Copy copyme content to base string location
    strncpy(*base,copyme,new_len);

    printf("The string at location %p is now %s\n", base, *base);

}

void main(){

    //Declare iterator
    int i;

    //Generate strings
    char first_lit[]="Fortran?";
    char second[]="Now that's a name I've not heard in a long time.";
    //int testint=5;

    //Capture elements of first_lit in pointer array (so we can get at the pointer to the strings pointer)
    char *first; //Declare pointer to pointer array that represents the first string
    first=malloc((strlen(first_lit)+1)*sizeof(char)); //Allocate space for the pointer array
    strncpy(first,first_lit,strlen(first_lit)); //Assign values to the pointer locations

    //Copy copyme into base
    printf("Initiating copy operation...\n");
    astrncpy(&first,second);
}

根据 C11 标准,章节 §7.22.3.5,realloc() 规范,(强调我的

void *realloc(void *ptr, size_t size);

If ptr is a null pointer, the realloc() function behaves like the malloc() function for the specified size. Otherwise, if ptr does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to the free() or realloc() function, the behavior is undefined. [...]

在您的例子中,*base 不是 return 由 malloc() 和家人编辑的指针。因此 undefined behavior。然后出现分段错误。

也就是说,在 main() 内部,first 的分配看起来也有问题。 first 作为一个 char ** 内存分配应该看起来像

first = malloc(sizeof(*first) * num_of_pointers_needed);

而不是

first=malloc(strlen(first_lit)*sizeof(char));

此外,在使用 returned 指针之前,您应该始终检查 malloc() 和家族的 return 值是否为 NULL 以确保成功。

最后,像

这样的语法
 p = realloc(p, newsize);

非常危险,因为万一 realloc() 失败,您将通过将 realloc()return 值分配给同一指针而最终丢失实际指针。再次引用标准,

[...] If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

The realloc() function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

你应该总是在一些临时指针中收集 realloc() 的 return 值,执行成功检查并在成功的情况下将其分配回实际指针。

From what I understand, this occurs if the pointer array is either not NULL, or is not the product of malloc().

第一部分不对。第二部分是对的。 realloc 的参数可以为 NULL。如果它不是 NULL,则它必须是 malloc 函数族返回的值。

您的代码存在问题,main 中的 *first 不是 mallocrealloc 返回的值。它只是一个指向 main.

中数组的指针

您正在传递指向堆栈中分配的内存的指针,试图重新分配它。这是错误的。您应该首先 malloc() string 然后尝试 realloc() 它。

查看这些声明

first=malloc(strlen(first_lit)*sizeof(char)); //Allocate space for the pointer array
*first=first_lit; //Assign values to the pointer locations

看来你认为你可以将数组与其他数组一起赋值。

这是一个错误的假设。您只能将一个数组的元素复制到另一个数组中。

还要考虑到您将函数命名为

astrncpy
    ^^

但通常这种中间带有n的函数有一个size_t类型的参数。您的函数没有这样的参数。所以最好把它命名为

astrcpy

函数名中间没有n

通常还有字符串函数 return 指向目标字符串的指针。

你的意思如下

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char * astrcpy( char **base, const char *copyme )
{
    printf( "Copying '%s' into a location currently featuring the following string: '%s'\n", copyme,*base );
    printf( "The location of our string to be copied (%s) is %p.\n", copyme, ( const void * )copyme );
    printf( "The location of our string to be replaced (%s) is %p.\n", *base,  ( void * )*base );

    //Declare string length variable
    size_t new_len = strlen( copyme );
    printf("Calculating new length for replaced memory allocation (%zu).\n", new_len );

    //Reallocate pointer array
    printf("Reallocating memory allocation.\n");

    char *tmp;
    if ( ( tmp = realloc( *base, sizeof( char ) * ( new_len + 1 ) ) ) != NULL )
    {
        *base = tmp;

        //Copy copyme content to base string location
        strcpy( *base, copyme );

        printf( "The string at location %p is now %s\n", ( void * )*base, *base );
    }

    return tmp;
}

int main( void )
{
    //Generate strings
    char first_lit[] = "Fortran?";
    char second[] = "Now that's a name I've not heard in a long time.";

    //Convert first string to array (so we can get at the pointer to the strings pointer)
    char *first; //Declare pointer to pointer array that represents the first string

    first = malloc( ( strlen( first_lit ) + 1 ) * sizeof( char ) ); //Allocate space for the pointer array
    strcpy( first, first_lit ); //Assign values to the pointer locations

    //Copy copyme into base
    if ( astrcpy( &first, second ) ) puts( first );

    free( first );
}

程序输出为

Copying 'Now that's a name I've not heard in a long time.' into a location currently featuring the following string: 'Fortran?'
The location of our string to be copied (Now that's a name I've not heard in a long time.) is 0x7ffe4b3d23d0.
The location of our string to be replaced (Fortran?) is 0x6da010.
Calculating new length for replaced memory allocation (48).
Reallocating memory allocation.
The string at location 0x6da010 is now Now that's a name I've not heard in a long time.
Now that's a name I've not heard in a long time.

有趣的是函数realloc并没有改变内存的起始地址。它只是放大了它。:)

重新分配之前

The location of our string to be replaced (Fortran?) is 0x6da010.

和realloc之后

The string at location 0x6da010 is now Now that's a name I've not heard in a long time.

地址相同0x6da010

关于这个问题

I am not clear, however, on why I can't get there with first_lit instead of having to construct first

那么你不能移动具有静态或自动存储持续时间的数组。您只能重新分配动态分配的内存并在那里复制一个数组。

因此您不能为 first_lit 重新分配内存。您可以动态分配内存并将数组的元素复制到那里first_lit,然后您可以重新分配这个动态分配的内存。