【问题标题】:Memory allocation doubt with type pointer to char类型指针指向 char 的内存分配疑问
【发布时间】:2011-11-26 08:14:21
【问题描述】:

这个程序应该提示输入单词中的字母数量(稍后输入),因此它知道要分配多少空间。它似乎工作正常,但是如果您分配的内存少于存储单词所需的内存,这似乎并不重要。 这是我必须纠正的错误还是因为指向 char (char *) 的指针就是这样工作的?

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

int main() 
{
unsigned int a = 0;
printf("Enter the size of the word(0=exit) :");
scanf("%d",&a);
if(a==0){return 0;}
else
     {
      char *word = (char *)malloc(a*sizeof(char) + 1);
      if(word == NULL)
          {
           fprintf(stderr,"no memory allocated");
           return 1;
          }
      printf("Reserved %d bytes of space (accounting for the end-character).\nEnter your word: ", a*sizeof(char) + 1);
      scanf("%s", word);
      printf("The word is: %s\n", word);
     }

return 0;
}

好吧,我想我可能已经修复了它,这样,使用 valgrind 运行不会显示它之前显示的任何错误。

char aux[]="";
  scanf("%s", aux);

  if(strlen(aux)>(a*sizeof(char) + 1))
     {
  fprintf(stderr,"Word bigger than memory allocated\nExiting program\n");
  return 1;
     }
  else
     {
      strcpy(word,aux);
      printf("The word is: %s\nAnd is %d characters long\n", word, strlen(word));
     }

现在我的疑问是:为什么我可以声明一个空的 char 数组(char aux[] = ""),然后使用没有错误的“额外”内存(在 valgrind 输出中)然而 char *aux = "";给我一个分段错误? 我对 C 编程很陌生,所以如果这是明显/愚蠢的问题,我很抱歉。 谢谢。

【问题讨论】:

  • scanf("%s", word) 本质上是不安全的。如果用户输入的字符多于您分配的空间,无论多多,都会导致缓冲区溢出。

标签: c pointers memory-management malloc arrays


【解决方案1】:

是的,您必须纠正程序中的错误。

当您分配的内存少于您的需要,然后访问“额外”内存时,程序进入未定义行为模式。它可能看起来可以工作,或者它可能会崩溃,或者它可能会做任何意想不到的事情。基本上,在写入未分配的额外内存后,什么都没有得到保证。

[更新:]

我建议从文件中读取任意长度的字符串是以下代码。我无法避免它有点长,但由于标准 C 不提供良好的字符串数据类型,我必须自己完成整个内存管理工作。所以这里是:

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

/** Reads a string from a file and dynamically allocates memory for it. */
int fagetln(FILE *f, /*@out*/ char **s, /*@out*/ size_t *ssize)
{
  char *buf;
  size_t bufsize, index;
  int c;

  bufsize = 128;
  if ((buf = malloc(bufsize)) == NULL) {
    return -1;
  }

  index = 0;
  while ((c = fgetc(f)) != EOF && c != '\n') {
    if (!(index + 1 < bufsize)) {
      bufsize *= 2;
      char *newbuf = realloc(buf, bufsize);
      if (newbuf == NULL) {
        free(buf);
        return -1;
      }
      buf = newbuf;
    }
    assert(index < bufsize);
    buf[index++] = c;
  }

  *s = buf;
  *ssize = index;
  assert(index < bufsize);
  buf[index++] = '\0';
  return ferror(f) ? -1 : 0;
}

int main(void)
{
  char *s;
  size_t slen;

  if (fagetln(stdin, &s, &slen) != -1) {
    printf("%zu bytes: %s\n", slen, s);
  }
  return 0;
}

【讨论】:

  • 不仅如此。该行为对您来说是未定义的,但黑客可能知道它。在某些情况下,他们可以输入一个“单词”,让他们可以控制您的程序并做您不打算做的事情。
  • 感谢您的快速回答,但我怎样才能做到这一点而不背叛分配该内存的目的?我不想使用 scanf 来存储另一个变量,检查它的大小,然后将其传递给 malloc 返回的指针的地址。
  • 我用一些示例代码更新了我的答案。我想到的另一种选择是将最大字符串长度传递给fscanf(如fscanf("%80s", word)),但是您必须自己组装格式字符串,这比编写易于使用的字符串还要丑陋具有漂亮界面的功能。
【解决方案2】:

这似乎无关紧要,但确实如此,如果您使用的空间多于分配的空间,您最终会以缓冲区溢出结束。您当前的实现分配的分配可能比您实际请求的要多,也可能没有。你不能继续这种行为,永远不要访问/使用未分配的内存。

根据定义也是sizeof( char ) == 1

【讨论】:

  • 我知道 char 只有 1 个字节,我只是习惯于为任何类型的跨架构目的这样做。
  • @JIM:在每个平台中,sizeof(char) 返回 1,由标准规定。
【解决方案3】:

当您free 缓冲区时,通常(但不总是)分配缓冲区的溢出会导致崩溃。如果您在末尾添加free(word),您可能会看到崩溃。

【讨论】:

    猜你喜欢
    • 2011-05-23
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2021-04-15
    • 2011-04-02
    相关资源
    最近更新 更多