字符与在C数组 [英] characters versus arrays in c

查看:91
本文介绍了字符与在C数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么1,2,3工作的时候产生4分割故障? (见下文)。

 字符C [10];
字符* D;

1

  scanf函数(%S,和C);
的printf(%S \\ n,和C);

2

  scanf函数(%S,C);
的printf(%S \\ n,C);

3。

  scanf函数(%S,和D);
的printf(%S \\ n,和D);

4。

  scanf函数(%S,D);
的printf(%S \\ n,D);


解决方案

在重复code的问题:

 字符C [10];
字符* D;

1

  scanf函数(%S,和C);
的printf(%S \\ n,和C);

这是有可能如预期的那样工作,但实际上的行为是不确定的。

scanf函数%S格式需要类型的参数的char * 和C 的类型为字符(*)[10] ,也就是说,它是一个指向的char [10] 阵列。它指向内存中的相同位置的第0个元素的ç的地址,但它是一个不同的类型。同样的事情发生在的printf :在%S格式,告诉它​​期望的char * 的说法,但你传递一个字符(*)[10] 参数。

由于 scanf函数是一个可变参数函数,没有必需的类型检查比格式字符串其他参数。编译器将(可能)高兴地通过字符(*)[10] scanf函数,假设它可以处理它。它的可能的可能,尽管在那里所有的指针具有相同的尺寸,重presentation和参数传递机制的实现。但是,例如,C编译器为异国情调的建筑能够很容易地使的char * 指针不是指针,以更大的类型更大。想象一下,一个CPU的母语地址指向,也就是说,一个64位字;一个的char * 指针可能会由一个字指针加一个字节偏移。

2

  scanf函数(%S,C);
的printf(%S \\ n,C);

这是更好的。 C 是一个数组,但在这种情况下一个数组前pression衰变的指针数组的第一个元素 - 而这正是 scanf函数%S格式要求。同样的事情发生过 C 的printf 。 (但仍存在一些问题;另一个例子后,我会得到那个

3。

  scanf函数(%S,和D);
的printf(%S \\ n,和D);

由于 D 是一个的char * 参数,和D 的类型为的char ** ,并再次,你传递错误类型的参数。如果所有的指针都具有相同的重presentation(和相同的参数传递机制),并为 scanf函数足够短,这可能发生的工作输入。它把在的char * 对象,就好像它是字符的数组。如果的char * 是4个字节,输入字符串不超过3个字符长,这将可能工作 - 因为如果你已经使用了 CHAR [4] ,正确书写的电话。但它的非常的差的做法来存储字符串直接进入一个指针对象,并有一个巨大的写过去的对象年底,未predictable结果的风险。 (那些未predictable结果包括写入到一个没有被用于其他任何记忆,这可能的显示的工作;这就是未定义行为的性质)

(C标准给予治疗任何对象作为一个字符数组特别许可,但在这种情况下,这是一个非常糟糕的主意。)

4。

  scanf函数(%S,D);
的printf(%S \\ n,D);

下面的类型是正确的,但除非你初始化 D 来指向一个足够大阵字符,它很可能会失败壮观(或者更糟糕,出现工作正确的,这意味着你已经有了一个微妙的错误,可能会出现更高版本)。

而现在我们得到什么,我对上述其他问题提及。

例如4中,我提到 D 需要指向一个足够大数组。有多大足够大?有没有答案。 scanf函数(%S,...)读取字符的,在其长度没有上限一空格分隔的序列。如果我运行您的程序并按住 X 键,例如,我可以提供一个输入字符串比你所提供的任何缓冲时间越长,与联合国predictable结果(再次未定义行为)。

scanf函数函数的%S格式的无法的安全使用(除非你的程序的环境下,你可以控制会出现什么样的标准输入流)中运行。

阅读文本输入的一个好方法是使用与fgets 来一次读取一行,然后使用其他功能来分析结果。 与fgets 要求您指定输入的最大长度;如果实际投入超过极限,它截断,并留待以后调用读取。它并不像 scanf函数一样方便,但它可以安全地完成。 (和的从不的使用获得功能;如 scanf函数(%S,...),它不能被安全地使用。)

推荐阅读:

第6 comp.lang.c常见问题地解释C数组和指针的表现非常出色,和他们是如何相关的(和不相关)。第12章讨论了C标准I / O。

(对不起,这个答案是这么久,我没有时间把它缩短。)

Why do 1, 2, and 3 work when 4 generates a segmentation fault? (See below.)

char c[10];
char* d;

1.

scanf("%s", &c);
printf("%s\n", &c);

2.

scanf("%s", c);
printf("%s\n", c);

3.

scanf("%s", &d);
printf("%s\n", &d);

4.

scanf("%s", d);
printf("%s\n", d);

解决方案

Repeating the code in the question:

char c[10];
char* d;

1.

scanf("%s", &c);
printf("%s\n", &c);

This is likely to work as expected, but in fact the behavior is undefined.

scanf with a "%s" format requires an argument of type char*. &c is of type char (*)[10], i.e., it's a pointer to a char[10] array. It points to the same location in memory as the address of the 0th element of c, but it's of a different type. The same thing happens with the printf: the "%s" format tells it to expect a char* argument, but you're passing it a char(*)[10] argument.

Since scanf is a variadic function, there's no required type checking for arguments other than the format string. The compiler will (probably) happily pass the char (*)[10] value to scanf, assuming that it can handle it. And it probably can, on an implementation where all pointers have the same size, representation, and argument-passing mechanism. But, for example, a C compiler for an exotic architecture could easily make char* pointers bigger than pointers to larger types. Imagine a CPU whose native address points to, say, a 64-bit word; a char* pointer might be composed of a word pointer plus a byte offset.

2.

scanf("%s", c);
printf("%s\n", c);

This is better. c is an array, but in this context an array expression "decays" to a pointer to the array's first element -- which is exactly what scanf with a "%s" format requires. The same thing happens passing c to printf. (But there are still some problems; I'll get to that after the other examples.

3.

scanf("%s", &d);
printf("%s\n", &d);

Since d is a single char* argument, &d is of type char**, and again, you're passing arguments of the wrong type. If all pointers have the same representation (and the same argument-passing mechanism), and the input for the scanf is short enough, this might happen to "work". It treats the char* object as if it were an array of char. If char* is 4 bytes, and the input string is no more than 3 characters long, this will probably work -- as if you had used a char[4] and written the calls correctly. But it's extremely poor practice to store character strings directly into a pointer object, and there's a huge risk of writing past the end of the object, with unpredictable results. (Those unpredictable results include writing into memory that isn't being used for anything else, which could appear to work; such is the nature of undefined behavior.)

(The C standard gives special permission to treat any object as an array of characters, but in this case it's a very bad idea.)

4.

scanf("%s", d);
printf("%s\n", d);

Here the types are all correct, but unless you've initialized d to point to a sufficiently large array of char, it's likely to fail spectacularly (or, worse, appear to work "correctly", which means you've got a subtle bug that will probably show up later).

And now we get to what I mentioned above about other problems.

For example 4, I mentioned that d needs to point to a "sufficiently large" array. How large is "sufficiently large"? There's no answer to that. scanf("%s", ...) reads a whitespace-delimited sequence of characters with no upper bound on its length. If I run your program and hold down the x key, for example, I can provide an input string longer than any buffer you've provided, with unpredictable results (undefined behavior again).

The scanf function's "%s" format cannot be used safely (unless your program runs in an environment where you can control what will appear on the standard input stream).

One good way to read text input is to use fgets to read a line at a time, then use other functions to analyze the result. fgets requires you to specify the maximum length of the input; if the actual input exceeds the limit, it's truncated and left to be read by later calls. It's not quite as convenient as scanf, but it can be done safely. (And never use the gets function; like scanf("%s", ...), it cannot be used safely.)

Suggested reading:

Section 6 of the comp.lang.c FAQ does an excellent job of explaining C arrays and pointers, and how they're related (and not related). Section 12 discusses C standard I/O.

(I'm sorry this answer is so long; I didn't have time to make it shorter.)

这篇关于字符与在C数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆