繁体   English   中英

使用示例扫描C中的char

[英]Scanf a char in C with an example

我当时在Cplusplus上教程

有这个例子:

/* scanf example */
#include <stdio.h>

int main ()
{
  char str [80];
  int i;

  printf ("Enter your family name: ");
  scanf ("%79s",str);  
  printf ("Enter your age: ");
  scanf ("%d",&i);
  printf ("Mr. %s , %d years old.\n",str,i);
  printf ("Enter a hexadecimal number: ");
  scanf ("%x",&i);
  printf ("You have entered %#x (%d).\n",i,i);

  return 0;
}

我在我的Macbook上试过它,当我做“做例子”时我得到了这个错误;

example.c: In function ‘main’:
example.c:25: warning: format ‘%79s’ expects type ‘char *’, but argument 2 has type ‘char (*)[80]’

当我做“valgrind ./example”时,我得到了这个消息;

==1326== Memcheck, a memory error detector
==1326== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==1326== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==1326== Command: ./example
==1326== 
--1326-- ./example:
--1326-- dSYM directory is missing; consider using --dsymutil=yes
Enter your family name: Park
Enter your age: 20
Mr. Park, 20 years old.
==1326== 
==1326== HEAP SUMMARY:
==1326==     in use at exit: 8,280 bytes in 3 blocks
==1326==   total heap usage: 3 allocs, 0 frees, 8,280 bytes allocated
==1326== 
==1326== LEAK SUMMARY:
==1326==    definitely lost: 0 bytes in 0 blocks
==1326==    indirectly lost: 0 bytes in 0 blocks
==1326==      possibly lost: 0 bytes in 0 blocks
==1326==    still reachable: 8,280 bytes in 3 blocks
==1326==         suppressed: 0 bytes in 0 blocks
==1326== Rerun with --leak-check=full to see details of leaked memory
==1326== 
==1326== For counts of detected and suppressed errors, rerun with: -v
==1326== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

问题1. “ make example”给出了一个错误,但是程序执行了应做的事情。 那么这里的错误是什么?

问题2我做了很少的研究,并且我了解到你不能在C中分配一个char,因为char不可变。 这就是char与int或float或double的不同之处。 如果是这样,我怎么能在这里指定str?

问题3什么是Char数组? 我读了几篇文章,但是在这里我不明白它是如何工作的!!!

char str [80];

表示str最多可以占用80个字节,对不对? 那是什么

scanf ("%79s",str);  

非常感谢您的帮助,并祝您2014年愉快! :)

这个:

scanf ("%79s", str);

是指“读一个字符串( s ),但不使用的空间超过79个字符从指针开始我已经给你”之类的。 这是一种在读取字符串时防止缓冲区溢出的方法。 它使用79而不是80来为字符串终止符留出空间。

文件说:

字符串输入转换存储一个终止的空字节( '\\0' )来标记输入的结尾。 最大字段宽度不包括此终止符。

我当时在Cplusplus上教程

请不要 该网站充满了错误,不正确和/或误导性的例子。 帮自己一个忙,然后选择另一个站点。

我在我的Macbook上试过它,当我做“做例子”时我得到了这个错误;

可能是您拼错了源代码,并且您写了&str而不是str (我认为这是一个坏习惯:抛出address-of运算符时不考虑遇到scanf() )。 这导致指向数组的指针,而转换说明符期望指向字符的指针。

“make example”会出错,但程序会执行它应该执行的操作。 那么这里的错误是什么?

该计划没有做它应该做的事情。 而是,它调用未定义的行为,假装正常工作。

我做了很少的研究,但我知道您不能在C中分配字符,因为字符是不可变的

错误。

什么是字符数组?

您的示例中的char数组是str 就是这样:80个字符阵列。 不幸的是,数组在C中有一些奇怪的属性,比如在传递给函数时隐式地衰减成指针。 这就是scanf()希望您传递指针而不是数组参数的原因:编写时

scanf("format string", str);

那么实际传递的是指向str第一个元素的指针(又名&str[0] )。


此外,如果您接受另一条好建议: 不要使用scanf() 这很危险,其用法违反直觉,并且总体上没有任何好处。 为了接受用户输入,请考虑改用fgets()

错误

example.c:25: warning: format ‘%79s’ expects type ‘char *’, but argument 2 has type ‘char (*)[80]’

只有你写过类似的东西才有意义

scanf ("%79s", &str); // wrong

代替

scanf ("%79s",str);  // right

您发布的代码是您实际编译的内容吗?

至于你的具体问题:

问题1.“制作示例”给出了错误,但程序执行了它应该做的事情。 那么这里的错误是什么?

首先,有一点背景知识:除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则将转换类型为“ T N元素数组”的表达式(“衰减”)类型为“指向T指针”的表达式,该表达式的值将是数组第一个元素的地址。

当你写作

scanf("%79s", str);

表达式str具有类型“80-element char of char ”; 因为str不是sizeof或一元&运算符的操作数,所以它被转换为“指向char指针”或char *类型的表达式,并且它的值是数组中第一个元素的地址。

如果你写过

scanf("%79s", &str);

表达式str是一元&运算符的操作数,因此不会发生转换; 相反,表达式&str的类型是“指向80个元素的 char 数组 ”,或者是char (*)[80] (看起来很熟悉?),表达式的值是数组的地址。

现在,恰好相反,数组的地址和数组的第一个元素的地址是相同的; 表达式str&str将产生相同的 ,但是两个表达式的类型不同。

因此,假设你写scanf("%79s, &str)代码将仍然是‘工作’(该值&str相同str ),但由于该类型是不是想让scanf预计为%s转换符,编译器会发出警告。

问题2我做了很少的研究,并且我了解到你不能在C中分配一个char,因为char不可变。 这就是char与int或float或double的不同之处。 如果是这样,我怎么能在这里指定str?

要么你误解了,要么你正在读一个非常糟糕的参考。 C中的字符串不是不可变的。 尝试修改字符串文字的内容会调用未定义的行为(某些平台会引发异常,有些平台不会),但这与说它们不可改变(就像Java字符串不可改变一样)不同。

C中的字符串存储为char数组。 您可以使用strcpy库函数或直接修改数组元素来更新字符串内容。 例如:

char str[80];
...
strcpy( str, "a string" );

将字符串文字"a string"的内容复制到str 你当然可以更新这个字符串,例如

str[0] = 'A'; // str now contains "A string"

或者向它添加另一个字符串:

strcat( str, " with more stuff" ); // str now contains "A string with more stuff"

"a string"这样的字符串文字存储为char数组,以便在程序启动时保存它们的存储,直到程序退出,并且它们在整个程序中可见。 尝试修改字符串文字的内容会调用未定义的行为; 它可能工作,它可能不会,编译器可能会抛出错误,您可能会在运行时收到错误。 所以你不想做类似的事情

char *p = "This is a test";
strcpy( p, "This is another test" );
问题3什么是Char数组? 我读了几篇文章,但是在这里我不明白它是如何工作的!!!
 char str [80]; 
表示str最多可以占用80个字节,对不对?

它需要80个char ; char映射到本地8位字节通常是正确的,但是也有例外(大多数情况是非常老的体系结构或奇数嵌入式系统)。

那是什么
 scanf ("%79s",str); 

在该调用中,所有scanf接收的是指向目标缓冲区的第一个元素的指针; 它不知道目标缓冲区实际有多大。 如果你写

scanf("%s", str);

并且用户输入的字符串长度超过80个字符, scanf会在str结束后立即将这些多余的字符愉快地存储到内存中,从而可能破坏重要内容并导致崩溃(或更糟糕的是,恶意软件利用)。 %79s指示scanf仅从输入流中读取最多79个字符。 为什么用79代替80? 您需要保留一个可用于0终止符的元素(在C中, 字符串是由0值字节终止的字符序列)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM