重新分配只能工作两次

时间:2019-10-09 04:31:41

标签: c realloc

由于某种原因,当我重新分配数组以将项目追加到数组时,它在段错误之前只能工作两次。当我尝试在数组内部打印字符串时,将发生段错误。我目前有一个NULL终止的数组。

void apparr(char** arr, char* line) {
    int length = 0;
    // find the length of the array
    while(arr[length] != NULL) {
        length++;
    }
    // realloc with 2 extra spaces (1 for line, 1 for NULL)
    arr = realloc(arr, sizeof(char*) * (length+2));
    // set last element (which was NULL) to line
    arr[length] = line;
    // set the NULL terminator
    arr[length+1] = NULL;
}

我不知道我可能在哪里出错,我唯一的猜测就是如何调用realloc。但是,我会理解这不适用于1个调整大小,但是我不知道为什么当我打印回阵列时,此方法适用于两个调整大小,然后是段错误。

它如何在main中使用:

int main(int argc, char** argv){
char** hist = malloc(sizeof(char**));
char* linep1;
char* linep2;
char* linep3;
char* linep4;
linep1 = (char*)malloc(strlen("test")*sizeof(char));
linep2 = (char*)malloc(strlen("test2")*sizeof(char));
linep3 = (char*)malloc(strlen("test3")*sizeof(char));
linep4 = (char*)malloc(strlen("test4")*sizeof(char));   
strcpy(linep1, "test");
strcpy(linep2, "test2");
strcpy(linep3, "test3");
strcpy(linep4, "test4");
apphist(hist, linep1);
apphist(hist, linep2);
//apphist(hist, linep3); //uncommenting this line causes nothing to be printed
//apphist(hist, linep4); //uncommenting this line causes only test4 to be printed
int x = 0;
while (hist[x] != NULL) {
    printf("%s\n", hist[x]);
    x++;
}
}

5 个答案:

答案 0 :(得分:2)

  1. 在主要功能中,您需要在功能hist中检查NULL的第一个元素为apphist

    char** hist = malloc(sizeof(char*));
    *hist = NULL;
    
  2. 函数apphist仅在本地更改arr的值。为了反映主要功能的变化,您需要将指针传递到arr,即3D指针char ***arr

  3. 您应始终检查realloc的结果并在失败时执行操作。

该功能的代码如下。

void apparr(char*** arr2, char* line) {
    int length = 0;
    char **arr = *arr2;
    while(arr[length] != NULL) {
        length++;
    }
    arr = realloc(arr, sizeof(char*) * (length+2));
    if (arr == NULL) {
        exit(1); // handle error 
    }        
    *arr2 = arr;   
    arr[length] = line;
    arr[length+1] = NULL;
}
  1. 或者,您可以返回一个指向char指针的指针,并更新main中的值。
char** apparr(char** arr, char* line) {
    int length = 0;
    char **temp;
    while(arr[length] != NULL) {
        length++;
    }
    temp = realloc(arr, sizeof(char*) * (length+2));
    if (temp == NULL) {
        exit(1); // handle error 
    }
    arr = temp;
    arr[length] = line;
    arr[length+1] = NULL;
    return (arr);
}    

//in main
hist = apphist(hist, linep1);
hist = apphist(hist, linep2);

答案 1 :(得分:0)

我认为您应先取消引用arr,然后再用于realloc。另一个观察; sizeof(char *)通常在32位体系结构中为4,在64位体系中为8,而不是1。

答案 2 :(得分:0)

对于一般情况,我认为您只需要调用长度为+1的realloc

arr = realloc(arr, sizeof(char*) * (length+1));

这是因为从先前状态开始,您已经有空间用于NULL终止指针。使用代码,您正在提议发生的事情是这样的

//重新分配之前的状态

字符串字符串为空

// apparr()调用

字符串字符串NULL未定义未定义//重新分配

String String String undefined undefined // arr [length] = line;

String String String NULL未定义// // arr [length + 1] = NULL;

第一次运行(末尾悬空分配的节点),但是第二次由于额外的分配,它可能以多种方式崩溃。

答案 3 :(得分:0)

您的代码中有几个错误:

  1. 这是您的主要错误。您不会替换给定指针中的值。使用指向该指针的指针是正确的,但是您需要取消引用它。为此,您需要将指针传递到hist并在重新分配时取消引用:

    *arr = realloc(*arr, sizeof(char*) * (length + 2));
    
  2. 指针列表未初始化,在第一次分配后,您需要设置第一个指针:

    hist[0] = NULL;
    
  3. 您的测试字符串分配为1:

    linep1 = malloc((strlen("test") + 1) * sizeof(char));
    linep2 = malloc((strlen("test2") + 1) * sizeof(char));
    linep3 = malloc((strlen("test3") + 1) * sizeof(char));
    linep4 = malloc((strlen("test4") + 1) * sizeof(char));
    

其他说明:

  • 完整的minimal reproducable example中缺少包含项。
  • 名称apparr()是错误的,您在apphist()中叫main()
  • 检查任何分配的返回值是否为NULL,这意味着分配失败。
  • 您不使用argcargv,所以写int main(void)
  • 第一个分配的类型为“错误”,但它们都是指针,因此大小相同:char** hist = malloc(sizeof(char*));
  • 由于malloc()返回了指向void的指针,因此无需强制转换。可以来回分配指向void的指针和其他指针,而无需强制转换。
  • 您可以将malloc() / strcpy()对替换为strdup()
  • 您甚至可以像这样apphist()那样用字符串作为“立即”值调用apphist(hist, "test");
  • main()应该返回一个intEXIT_SUCCESS是正确的值。
  • 您可以在参数和声明中放置const,以使事情更安全。但是想想什么是常数。

答案 4 :(得分:0)

其他人已经提到了所有错误和可能的陷阱。

在下面找到一个附加元素到数组函数的更通用的实现:

#include <stdlib.h>
#include <errno.h> /* for EINVAL */

int apparr(char *** parr, char * line) {
  size_t length = 0;

  if (NULL == *parr) {
    if (NULL != line) {
      errno = EINVAL;
      return -1;
    }
  } else {
    // find the length of the array
    while (NULL != (*parr)[length]) {
      ++length;
    }
  }

  {
    // realloc with 2 extra spaces (1 for line, 1 for NULL)
    void * pv = realloc(*parr, (length+1) * sizeof **parr);
    if (NULL == pv) {
      return -1; /* By convention -1 indicates failure. */
    }

    *parr = pv;
  }

  (*parr)[length] = line;
  if (0 < length) {
    (*parr)[length + 1] = NULL;
  }

  return 0; /* By convention 0 indicates success. */
}

并像这样使用它:

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

int apparr(char *** parr, char * line) {

int main(int argc, char** argv) {
  char ** hist = NULL;
  char * linep1;
  char * linep2;
  char * linep3;
  char * linep4;

  if (-1 == apparr(&hist, NULL)) {
    perror("apphist() failed initially\n");
    exit(EXIT_FAILURE);
  }

  linep1 = malloc(strlen("test") + 1);
  linep2 = malloc(strlen("test2") + 1); /* +1 for the c-string's 0-termination; sizeof (char) is 1 by definition */
  linep3 = malloc(strlen("test3") + 1);
  linep4 = malloc(strlen("test4") + 1);

  strcpy(linep1, "test");
  strcpy(linep2, "test2");
  strcpy(linep3, "test3");
  strcpy(linep4, "test4");

  if (-1 == apphist(&hist, linep1)) {
    perror("apphist() failed for line 1\n");
    exit(EXIT_FAILURE);
  }

  if (-1 == apphist(&hist, linep2) {
    perror("apphist() failed for line 2\n");
    exit(EXIT_FAILURE);
  }

  if (-1 == apphist(&hist, linep3) {
    perror("apphist() failed for line 3\n");
    exit(EXIT_FAILURE);
  }

  if (-1 == apphist(&hist, linep4)  {
    perror("apphist() failed for line 4\n");
    exit(EXIT_FAILURE);
  }

  {
    size_t x = 0;
    while (hist[x] != NULL) {
      printf("%s\n", hist[x]);
      ++x;
    }
  }
}