【问题标题】:End of integer/structure array?整数/结构数组的结尾?
【发布时间】:2015-04-30 15:07:00
【问题描述】:
Consider the following functions
void alloco(int **ppa)
{
    int i;
    printf("inside alloco %d\n",ppa); /*this function allocates and fills 20 * sizeof(int) bytes */
    *ppa = (int *)malloc(20 * sizeof(int));
    /*fill all 20 * sizeof(int) bytes */
}

int main()
{
    int *app = NULL;
    int i;
    printf("inside main\n");
    alloco(&app);
    for(i=0;i<20;i++) /*ISSUE::how will i know to traverse only 20 indexes?*/
    printf("app[%d] = %d \n", i, app[i]);
    return(0);
}

基本上 main() 将如何知道要遍历的字节数,即 alloco() 函数分配的内存。字符数组中是否有像 NULL 这样的分隔符?

【问题讨论】:

  • 如果你真的需要在不传递大小的情况下执行此操作,那么你需要自己填充分隔符,或者需要依赖 malloc 的平台特定实现来访问标题。
  • C-"strings" (char arrays) 由 NUL aka null aka '\0' 终止,但肯定不是由NULL 终止,后者是不同的。跨度>
  • 如果这种模式经常出现,您可能需要一个结构来跟踪其第二个成员(指针)所指向的数据长度。或者您使用在其标准库中具有该结构的语言;-)

标签: c pointers pointer-to-pointer pass-by-pointer


【解决方案1】:

这是不可能的,您需要将该值保存在某个地方,例如您可以这样做,

void alloco(int **ppa, int count)
{
    int i;

    printf("inside alloco %d\n",ppa);
    *ppa = malloc(count * sizeof(int));
    if (*ppa == NULL)
        return;
    for (i = 0 ; i < count ; ++i)
        /* fill it here. */
}

int main()
{
    int *app;
    int  i;
    int  count;

    count = 20;
    app = NULL;
    printf("Inside main\n");
    alloco(&app, count);
    if (app == NULL)
        return -1;    
    for (i = 0 ; i < count ; i++)
        printf("app[%d] = %d \n", i, app[i]);
    /* done with `app' */
    free(app);
    return 0;
}

许多其他组合也可以使用,例如

int alloco(int **ppa)
{
    int i;

    printf("inside alloco %d\n",ppa);
    *ppa = malloc(20 * sizeof(int));
    if (*ppa == NULL)
        return;
    for (i = 0 ; i < count ; ++i)
        /* fill it here. */
    return 20;
}

int main()
{
    int *app;
    int  i;
    int  count;

    printf("Inside main\n");

    app = NULL;
    count = alloco(&app);
    if (app == NULL)
        return -1;    
    for (i = 0 ; i < count ; i++)
        printf("app[%d] = %d \n", i, app[i]);
    /* done with `app' */
    free(app);
    return 0;
}

但我个人不喜欢这样,因为如果整数的数量是固定的,那么只使用malloc() 并不是一个好主意,

int main()
{
    int  app[20];
    int  i;

    printf("Inside main\n");    
    for (i = 0 ; i < sizeof(app) / sizeof(app[0]) ; i++)
        printf("app[%d] = %d \n", i, app[i]);
    return 0;
}

【讨论】:

  • 你确定吗?如果是这种情况,那么您使用的“count”变量在我的情况下需要由 alloco 定义,所以我需要通过引用将此计数传递给 alloco 函数,对吗?
  • 不一定,我认为您正在尝试使用其他编程语言的想法来做某事,您能解释一下为什么要这样做吗?参见我提出的第二种解决方案,在分配器函数中决定缓冲区大小是非常糟糕的设计,没有多大意义。
  • 不,不是那样的,我的要求是这样的——main() 给 alloco() 一个 NULL 指针,alloco 需要填充它(基于其他一些函数的输出)并告诉 main( ) 直到阅读的地方(如果你是正确的)。
  • :D 我的用例就是这样,因此问题。 @iharob
  • 看来您的意思是传递和设置 &count,而不是 count。
【解决方案2】:

字符数组中是否有类似 NULL 的分隔符?

如果你定义一个,是的。

这只有在您的用例不需要所有可能的整数值时才有可能。

例如,如果您只需要包括0 在内的正值,则可以将-1 的值定义为“数组结束”标记。

然后,您需要为数组再分配一个元素,然后将-1 分配给这个额外的最后一个数组元素。

示例:

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

#define EOA (-1)

int array_allocate(int ** ppi)
{
  int result = 0;

  if (NULL = ppi)
  {
    result = -1;
    errno = EINVAL;
  }
  else
  {
    size_t number_of_elements = ...; /* Assign some positive value here. */

    *ppi = malloc((number_of_elements + 1) * sizeof ** ppi);
    if (NULL == *ppi)
    {
      result = -1;
    }
    else
    {
      (*ppi)[number_of_elements] = EOA;
    }
  }

  return result;
}

ssize_t array_number_of_elements(int * pi)
{
  int result = 0;

  if (NULL == pi)
  {
    result = -1;
    errno = EINVAL;
  }
  else
  {
    int * pi_tmp = pi;
    while (EOA != *pi_tmp)
    {
      ++pi_tmp;
    }

    result = pi_tmp - pi;
  }

  return result;
}

像这样使用它:

#include <stdlib.h> /* for size_t and ssize_t */
#include <stdio.h> /* for printf and perror */

int array_allocate(int **);
ssize_t array_number_of_elements(int *);

int main(void)
{
  int result = EXIT_SUCCESS;
  int * pi = NULL;

  if (-1 == array_allocate(&pi))
  {
    result = EXIT_FAILURE;
    perror("array_allocate() failed");
  }
  else
  {
    ssize_t result_number_of_elements = array_number_of_elements(pi);
    if (-1 == result_number_of_elements)
    {
      result = EXIT_FAILURE;
      perror("array_number_of_elements() failed");
    }
    else
    {
      size_t number_of_elements = result_number_of_elements;
      printf("The number of array's elements is %zu.\n", 
        number_of_elements);
    }
  }

  free(pi); /* Clean up. */

  return result;
}

【讨论】:

    【解决方案3】:

    成为一名三星级程序员

    您可以轻松地在函数中分配一些固定数量的元素(小于最大值),而无需在调用者函数和被调用者之间传递元素数量。但是,它需要创建一个指向类型指针的指针数组如何/为什么?本质上,您将数组视为以空字符结尾的字符串,最初将数组中所有类型的指针分配给NULL,并且只根据需要为它们分配空间。 (使用calloc 进行分配使这变得轻而易举)当在调用者中使用该数组时,它允许迭代所有填充值,直到到达第一个空指针。

    现在授予,

    只需将 指向大小的指针作为附加参数传递给您的 函数更有意义 [1]

    并消除了对三星级评级的需要,但出于示例的目的,请享受一段时间的三星级程序员

    #include <stdio.h>
    #include <stdlib.h>
    
    #define INITSZ 21
    
    void alloco (int ***ppa)
    {
        printf("inside %s\n", __func__);
    
        int i = 0;
    
        /* allocate 21 pointers-to-int */
        if (!(*ppa = calloc (INITSZ, sizeof **ppa))) {
            fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
            exit (EXIT_FAILURE);
        }
    
        /* allocate/fill 20 values (or anything less than 21) */
        for (i = 0; i < INITSZ - 1; i++) {
            if (!((*ppa)[i] = calloc (1, sizeof ***ppa))) {
                fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
                exit (EXIT_FAILURE);
            }
            *((*ppa)[i]) = i * 2;
        }
    }
    
    int main()
    {
        int **app = NULL;
        int i = 0;
    
        printf ("inside main\n");
        alloco (&app);
    
        /*ISSUE::how will i know to traverse only 20 indexes?*/
    
        while (app[i]) {
            printf("app[%d] = %d \n", i, *(app[i]));
            i++;
        }
    
        return(0);
    }
    

    使用/输出

    $ ./bin/alloc_array+1
    inside main
    inside alloco
    app[0] = 0
    app[1] = 2
    app[2] = 4
    app[3] = 6
    app[4] = 8
    app[5] = 10
    app[6] = 12
    app[7] = 14
    app[8] = 16
    app[9] = 18
    app[10] = 20
    app[11] = 22
    app[12] = 24
    app[13] = 26
    app[14] = 28
    app[15] = 30
    app[16] = 32
    app[17] = 34
    app[18] = 36
    app[19] = 38
    

    脚注 [1]: 为清楚起见,在引文中添加了重点,即该解决方案旨在展示什么是可能的,而不是最有效或最实用的。

    【讨论】:

    • 您知道这种方法(至少在 64 位系统上)占用的内存是使用线性数组时的 3 倍。
    • 这里有两个错误:第一个:这个:(**ppa)[i] = i * 2; 应该是*((*ppa)[i]) = i * 2;` 第二个这个printf("app[%d] = ... (*app)[i]); 应该是printf("app[%d] = ... *(app[i]));
    • 我很欣赏这些错误修复。至于内存,这并不是作为效率候选者,而是作为对所提出的确切问题的不切实际的解决方案。这就是为什么它被明确限定为将指向大小的指针作为附加参数传递给函数更有意义。谢谢。
    猜你喜欢
    • 2014-05-09
    • 2013-07-29
    • 1970-01-01
    • 2014-12-30
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多