2011-09-27 62 views
0

该程序应该提示输入一个单词中的字母数(稍后输入),以便知道需要分配多少空间。它似乎可以正常工作,但是如果分配的内存少于要存储的单词所需的内存量,似乎并不重要。 这是一个错误,我必须纠正或是因为这是如何指针字符(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)); 
    } 

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

+2

'scanf(“%s”,word)'本质上是不安全的。如果用户输入的字符多于您为其分配空间的字符数量,则会出现缓冲区溢出。 –

回答

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; 
} 
+0

不仅如此。这个行为对你来说是未定义的,但它可能被黑客知道。在某些情况下,他们可以输入一个“单词”,可以让他们控制你的程序并做你不想做的事情。 – morningstar

+0

感谢您的快速回答,但我怎么能做到这一点而不背离分配内存的目的?我不想使用scanf来存储另一个变量,检查它的大小,然后将它传递给malloc返回的指针的地址。 –

+0

我用一些示例代码更新了我的答案。另一个我想到的选择是将最大字符串长度传递给'fscanf'(就像'fscanf(“%80s”,word)'),但是你必须自己组装这个格式字符串,那更丑陋而不是用一个漂亮的界面编写一个易于使用的功能。 –

0

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

1

它似乎并不重要,但它确实,如果您使用更多的空间而不是分配,您最终会以缓冲区溢出结束。有可能你现在的实现分配的比你实际请求的多一点,也有可能它没有。您无法在该行为上转播,也不能访问/使用未分配的内存。

还有sizeof(char) == 1的定义。

+0

我知道char只有1个字节,我只是习惯于为任何类型的跨体系结构目的而这样做。 –

+0

@JIM:在**每个**平台中,sizeof(char)'返回1,由标准决定。 –