2010-10-12 45 views
1

我的问题与此one完全相同。也就是说,我试图使用scanf()来接收一串不确定的长度,我想scanf()为它动态分配内存。使用scanf动态分配()

但是,在我的情况下,我使用VS2010。据我所知,MS的scanf()在扫描字符串时没有a或m修饰符。有没有办法做到这一点(除了一次接收一个字符)?

+0

GNU C Library支持'a'作为'分配内存'修饰符; GNU C Library版本2.8(我碰巧拥有的手册)没有提到'm'作为修饰符。这是自2.8以来的又一次增加吗? – 2010-10-12 04:05:35

+0

从2008-07-12 3.23版我的手册中提到了两者。 'm'修饰符是GNU扩展'a'的替代品,因为它与匹配浮点数的c99修饰符'a'相冲突。 – Frank 2010-10-12 04:20:37

+0

@Frank:下载更新的时间...谢谢。这是偶尔的非标准扩展的另一个缺点 - 标准通过标准化来改变非标准的含义。 – 2010-10-12 05:36:41

回答

1

如果你想使用scanf你可以只分配一个足够大的缓冲区来存放任何可能的值,即1024个字节,然后用1024

ma最大字段宽度说明符是特定非标准的GNU扩展,这就是为什么微软编译器不支持它们的原因。人们可能希望视觉工作室做到。

下面是一个使用scanf阅读设置,只打印他们回来了一个例子:

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

int 
main(int argc, char **argv) 
{ // usage ./a.out < settings.conf 

    char *varname; 
    int value, r, run = 1; 

    varname = malloc(1024); 

    // clear errno 
    errno = 0; 

    while(run) 
    { // match any number of "variable = #number" and do some "processing" 

     // the 1024 here is the maximum field width specifier. 
     r = scanf ("%1024s = %d", varname, &value); 
     if(r == 2) 
     { // matched both string and number 
      printf(" Variable %s is set to %d \n", varname, value); 
     } else { 
      // it did not, either there was an error in which case errno was 
      // set or we are out of variables to match 
      if(errno != 0) 
      { // an error has ocurred. 
       perror("scanf"); 
      } 
      run = 0; 
     } 
    } 

    return 0; 
} 

下面是一个例子settings.conf

cake = 5 
three = 3 
answertolifeuniverseandeverything = 42 
charcoal = -12 

你可以阅读更多关于scanf on the manpages

而你当然可以使用getline(),然后在字符之后解析字符。

如果你想进一步了解你想要达到的目标,你可能会得到更好的答案。

+0

我会解释如何编写一个字段宽度说明符,因为OP很可能不知道,只是忽略这个建议,造成缓冲区溢出漏洞...... – 2010-10-12 05:49:39

+0

对,我可能应该。但是OP代表什么? – Frank 2010-10-12 06:15:44

0

我认为,在现实世界中,需要对用户输入的长度有一些最大限制。

然后,您可以阅读整个行,如getline()。请参阅http://www.cplusplus.com/reference/iostream/istream/getline/

请注意,如果您要从用户输入多个数据,则不需要为每个数组分别分配char数组。你可以有一个大的缓冲区,例如char buffer[2048],与getline()一起使用,并将内容复制到适当分配(和命名)的变量,例如,像char * name = strdup(buffer)

+0

如果缓冲区不够大,那么让getline()为你分配一个缓冲区可能会更好,那么getline()会使它足够大。 – Frank 2010-10-12 04:28:04

2

绝对要用scanf?是不是std::string s; std::cin >> s;getline(std::cin, s);是您的选择?

0

请勿使用scanf来读取字符串。它甚至可能不会做你认为它所做的事情; %s只读直到下一个空格。

+1

不要这样,你的“答案”是没有帮助的。这家伙可能没有躺在周围的男人的网页,并要求他应该怎么做 - 而不是他应该如何**不**。 – Frank 2010-10-12 04:14:23

+0

@Frank:我认为关于'%s'和空白的观点是一个相当精明的观察! – 2010-10-12 04:51:13

+0

是的,你是对的,但也许这个人知道%s只会读取下一个空白,比如std :: cin。高可能有一些以前编译在* nix/GNU系统上的代码,并试图让它在他的vc​​10上运行。 如果我们有一些现有的代码可用于/显示,那将更容易。 – Frank 2010-10-12 05:06:51

4

scanf()的标准版本不会为其读取的任何变量分配内存。

如果您在某些scanf()版本中使用非标准扩展名被忽略,那么您刚开始学习如何编写可移植代码的第一课 - 不使用非标准扩展。您可以细微地说,“不要使用在您感兴趣的所有平台上不可用的扩展”,但要意识到随着时间的推移,这组平台可能会发生变化。

+0

+1,用于指出如何依赖不可移植的扩展来限制OP。 – 2010-10-12 05:48:46