简体   繁体   English

使用示例扫描C中的char

[英]Scanf a char in C with an example

I was doing a tutorial at Cplusplus 我当时在Cplusplus上教程

There was this example: 有这个例子:

/* 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;
}

I tried it on my Macbook and when I do "make example" I get this error; 我在我的Macbook上试过它,当我做“做例子”时我得到了这个错误;

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

When I do "valgrind ./example" I get this message; 当我做“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)

Question 1. The "make example" gives an error but the program does what it should do. 问题1. “ make example”给出了一个错误,但是程序执行了应做的事情。 Then what is the error here? 那么这里的错误是什么?

Question 2 I did little research and I learned that you can't assign a char in C since a char is not mutable. 问题2我做了很少的研究,并且我了解到你不能在C中分配一个char,因为char不可变。 That is what a char differs from int or float or double. 这就是char与int或float或double的不同之处。 If so, how could I have assigned str here? 如果是这样,我怎么能在这里指定str?

Question 3 What is the Char array? 问题3什么是Char数组? I read several articles but I don't get how it works here!!! 我读了几篇文章,但是在这里我不明白它是如何工作的!!!

char str [80];

means str can take up to 80 bytes, right? 表示str最多可以占用80个字节,对不对? Then what is 那是什么

scanf ("%79s",str);  

?

Thank you so much for your help guys and happy 2014! 非常感谢您的帮助,并祝您2014年愉快! :) :)

This: 这个:

scanf ("%79s", str);

means "read a string ( s ) but don't use more than 79 characters of space starting from the pointer I've given you", sort of. 是指“读一个字符串( s ),但不使用的空间超过79个字符从指针开始我已经给你”之类的。 It's a way to prevent buffer overflow when reading strings. 这是一种在读取字符串时防止缓冲区溢出的方法。 It's using 79 rather than 80 to leave room for the string terminator. 它使用79而不是80来为字符串终止符留出空间。

The documentation says: 文件说:

String input conversions store a terminating null byte ( '\\0' ) to mark the end of the input; 字符串输入转换存储一个终止的空字节( '\\0' )来标记输入的结尾。 the maximum field width does not include this terminator. 最大字段宽度不包括此终止符。

I was doing a tutorial at Cplusplus 我当时在Cplusplus上教程

Please don't. 请不要 That site is full of bad, incorrect and/or misleading examples. 该网站充满了错误,不正确和/或误导性的例子。 Do yourself a favor and choose another site. 帮自己一个忙,然后选择另一个站点。

I tried it on my Macbook and when I do "make example" I get this error; 我在我的Macbook上试过它,当我做“做例子”时我得到了这个错误;

Probably you misspelled the source code and you wrote &str instead of str (I think it's a bad habit: throwing in the address-of operator without thinking when you encounter scanf() ). 可能是您拼错了源代码,并且您写了&str而不是str (我认为这是一个坏习惯:抛出address-of运算符时不考虑遇到scanf() )。 That results in a pointer-to-array whereas the conversion specifier expects a pointer-to-char. 这导致指向数组的指针,而转换说明符期望指向字符的指针。

The "make example" gives an error but the program does what it should do. “make example”会出错,但程序会执行它应该执行的操作。 Then what is the error here? 那么这里的错误是什么?

The program does not do what it should. 该计划没有做它应该做的事情。 Instead, it invokes undefined behavior, and it pretends to work correctly. 而是,它调用未定义的行为,假装正常工作。

I did little research and I learned that you can't assign a char in C since a char is not mutable 我做了很少的研究,但我知道您不能在C中分配字符,因为字符是不可变的

Wrong. 错误。

What is the Char array? 什么是字符数组?

The char array in your example is str . 您的示例中的char数组是str It's just that: an array of 80 chars. 就是这样:80个字符阵列。 Unfortunately, arrays have some bizarre properties in C, such as implicitly decaying into pointers when passed to a function. 不幸的是,数组在C中有一些奇怪的属性,比如在传递给函数时隐式地衰减成指针。 That is the reason scanf() wants you to pass a pointer and not an array argument: when you write 这就是scanf()希望您传递指针而不是数组参数的原因:编写时

scanf("format string", str);

then what is actually passed is a pointer to the first element in str (aka &str[0] ). 那么实际传递的是指向str第一个元素的指针(又名&str[0] )。


Also, if you accept one more piece of good advice: don't use scanf() . 此外,如果您接受另一条好建议: 不要使用scanf() It's dangerous, its usage is counter-intuitive, and it doesn't do any good in general. 这很危险,其用法违反直觉,并且总体上没有任何好处。 For accepting user input, consider using fgets() instead. 为了接受用户输入,请考虑改用fgets()

The error 错误

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

only makes sense if you had written something like 只有你写过类似的东西才有意义

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

instead of 代替

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

Is the code you posted what you're actually compiling? 您发布的代码是您实际编译的内容吗?

As to your specific questions: 至于你的具体问题:

Question 1. The "make example" gives an error but the program does what it should do. 问题1.“制作示例”给出了错误,但程序执行了它应该做的事情。 Then what is the error here? 那么这里的错误是什么?

First, a little background: except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T " will be converted ("decay") to an expression of type "pointer to T ", and the value of the expression will be the address of the first element of the array. 首先,有一点背景知识:除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则将转换类型为“ T N元素数组”的表达式(“衰减”)类型为“指向T指针”的表达式,该表达式的值将是数组第一个元素的地址。

When you write 当你写作

scanf("%79s", str);

the expression str has type "80-element array of char "; 表达式str具有类型“80-element char of char ”; since str is not the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to char ", or char * , and its value is the address of the first element in the array. 因为str不是sizeof或一元&运算符的操作数,所以它被转换为“指向char指针”或char *类型的表达式,并且它的值是数组中第一个元素的地址。

If you had written 如果你写过

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

the expression str is the operand of the unary & operator, so the conversion doesn't happen; 表达式str是一元&运算符的操作数,因此不会发生转换; instead, the type of the expression &str is "pointer to 80-element array of char ", or char (*)[80] (look familiar?) and the value of the expression is the address of the array. 相反,表达式&str的类型是“指向80个元素的 char 数组 ”,或者是char (*)[80] (看起来很熟悉?),表达式的值是数组的地址。

Now, it just so happens that the address of an array and the address of the first element of an array are the same; 现在,恰好相反,数组的地址和数组的第一个元素的地址是相同的; the expressions str and &str will yield the same value , but the types of the two expressions are different. 表达式str&str将产生相同的 ,但是两个表达式的类型不同。

So, assuming you had written scanf("%79s, &str) , the code will still "work" (the value of &str is the same as str ), but since the type isn't want scanf expects for the %s conversion specifier, the compiler emits a warning. 因此,假设你写scanf("%79s, &str)代码将仍然是‘工作’(该值&str相同str ),但由于该类型是不是想让scanf预计为%s转换符,编译器会发出警告。

Question 2 I did little research and I learned that you can't assign a char in C since a char is not mutable. 问题2我做了很少的研究,并且我了解到你不能在C中分配一个char,因为char不可变。 That is what a char differs from int or float or double. 这就是char与int或float或double的不同之处。 If so, how could I have assigned str here? 如果是这样,我怎么能在这里指定str?

Either you've misunderstood, or you're reading a very bad reference. 要么你误解了,要么你正在读一个非常糟糕的参考。 Strings in C are not immutable; C中的字符串不是不可变的。 attempting to modify the contents of a string literal invokes undefined behavior (some platforms will throw an exception, some won't), but that's not the same as saying they are immutable in the same way Java strings are immutable. 尝试修改字符串文字的内容会调用未定义的行为(某些平台会引发异常,有些平台不会),但这与说它们不可改变(就像Java字符串不可改变一样)不同。

Strings in C are stored as arrays of char . C中的字符串存储为char数组。 You can update string contents by using the strcpy library function or by modifying the array elements directly. 您可以使用strcpy库函数或直接修改数组元素来更新字符串内容。 For example: 例如:

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

copies the contents of the string literal "a string" to str . 将字符串文字"a string"的内容复制到str You can certainly update this string, such as 你当然可以更新这个字符串,例如

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

or append another string to it: 或者向它添加另一个字符串:

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

String literals like "a string" are stored as arrays of char such that their storage is allocated when the program starts and held until the program exits, and they are visible over the entire program. "a string"这样的字符串文字存储为char数组,以便在程序启动时保存它们的存储,直到程序退出,并且它们在整个程序中可见。 Trying to modify the contents of a string literal invokes undefined behavior; 尝试修改字符串文字的内容会调用未定义的行为; it may work, it may not, the compiler may throw an error, you may get an error at runtime. 它可能工作,它可能不会,编译器可能会抛出错误,您可能会在运行时收到错误。 So you don't want to do something like 所以你不想做类似的事情

char *p = "This is a test";
strcpy( p, "This is another test" );
Question 3 What is the Char array? 问题3什么是Char数组? I read several articles but I don't get how it works here!!! 我读了几篇文章,但是在这里我不明白它是如何工作的!!!
 char str [80]; 
means str can take up to 80 bytes, right? 表示str最多可以占用80个字节,对不对?

It takes up 80 char s; 它需要80个char ; it's usually true that a char maps to a native 8-bit byte, but there are exceptions (mostly either very old architectures or oddball embedded systems). char映射到本地8位字节通常是正确的,但是也有例外(大多数情况是非常老的体系结构或奇数嵌入式系统)。

Then what is 那是什么
 scanf ("%79s",str); 
?

In that call, all scanf receives is a pointer to the first element of the target buffer; 在该调用中,所有scanf接收的是指向目标缓冲区的第一个元素的指针; it has no idea how big the target buffer actually is. 它不知道目标缓冲区实际有多大。 If you wrote 如果你写

scanf("%s", str);

and the user typed in a string that was more than 80 characters long, scanf would happily store those extra characters to the memory immediately following the end of str , potentially clobbering something important and leading to a crash (or worse, a malware exploit). 并且用户输入的字符串长度超过80个字符, scanf会在str结束后立即将这些多余的字符愉快地存储到内存中,从而可能破坏重要内容并导致崩溃(或更糟糕的是,恶意软件利用)。 The %79s directs scanf to only read up to 79 characters from the input stream. %79s指示scanf仅从输入流中读取最多79个字符。 Why 79 instead of 80? 为什么用79代替80? You need to leave one element available for the 0 terminator (in C, a string is a sequence of characters terminated by a 0-valued byte). 您需要保留一个可用于0终止符的元素(在C中, 字符串是由0值字节终止的字符序列)。

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

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