`
huoyj
  • 浏览: 87968 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

C语言问题(二)

阅读更多
1).为什么声明extern int f(struct x *p); 报出了一个奇怪的警告信息“结构x 在参数列表中声明”?
与C 语言通常的作用范围规则大相径庭的是, 在原型中第一次声明(甚至提到) 的结构不能和同一源文件中的其它结构兼容, 它在原型的结束出就超出了作用范围。
要解决这个问题, 在同一源文件的原型之前放上这样的声明:
struct x;
它在文件范围内提供了一个不完整的结构x 的声明, 这样, 后续的用到结构x的声明至少能够确定它们引用的是同一个结构x。
2).我不明白为什么我不能象这样在初始化和数组维度中使用常量:
const int n = 5; int a[n];
const 限定词真正的含义是“只读的”; 用它限定的对象是运行时(同常) 不能被赋值的对象。因此用const 限定的对象的值并不完全是一个真正的常量。在这点上C 和C++ 不一样。如果你需要真正的运行时常量, 使用预定义宏#define(或enum)。
3).警告信息“warning: macro replacement within a string literal”是什么意思?
有些ANSI 前的编译器/预处理器把下面这样的宏
#define TRACE(var, fmt) printf("TRACE: var = fmt\n", var)
解释为
TRACE(i, %d);
这样的调用会被扩展为
printf("TRACE: i = %d\n", i);
换言之, 字符串常量内部也作了宏参数扩展。
K&R 和标准C 都没有定义这样的宏扩展。当你希望把宏参数转成字符串时,
你可以使用新的预处理操作符# 和字符串常量连接(ANSI 的另一个新功能):
#define TRACE(var, fmt) \
printf("TRACE: " #var " = " #fmt "\n", var)
4).a[3] = "abc"; 合法吗?它是什么意思?
尽管只在极其有限的环境下有用, 可它在ANSI C (可能也包括一些ANSI 之前的系统) 中是合法的。它声明了一个长度为3 的数组, 把它的三个字符初始化为’a’, ’b’ 和’c’, 但却没有通常的’\0’ 字符。因此该数组并不是一个真正的C 字符串从而不能用在strcpy,
printf %s 等当中。
多数时候, 你应该让编译器计算数组初始化的初始值个数, 在初始值“abc” 中,计算得长度当然应该是4。
5).memcpy() 和memmove() 有什么区别?
如果源和目的参数有重叠, memmove() 提供有保证的行为。而memcpy()则不能提供这样的保证, 因此可以实现得更加有效率。如果有疑问, 最好使用memmove()。
malloc(0) 有什么用?返回一个控指针还是指向0 字节的指针?
ANSI/ISO 标准声称它可能返回任意一种; 其行为由实现定义。

6).这样的代码有什么问题?char c; while((c = getchar()) != EOF)
...
第一, 保存getchar 的返回值的变量必须是int 型。getchar() 可能返回任何字
符值, 包括EOF。如果把getchar 的返回值截为char 型, 则正常的字符可能会被
错误的解释为EOF, 或者EOF 可能会被修改(尤其是char 型为无符号的时候), 从
而永不出现。

2.为什么这些代码
while(!feof(infp)) { fgets(buf, MAXLINE,infp); fputs(buf, outfp); } 把最后一行复制了两遍?
在C 语言中, 只有输入例程试图读并失败以后才能得到文件结束符。换言之,C 的I/O 和Pascal 的不一样。通常你只需要检查输入例程的返回值, 例如, fgets()在遇到文件结束符的时候返回NULL。实际上, 在任何情况下, 都完全没有必要使用feof()。
3.我如何在printf 的格式串中输出一个’%’?我试过\%, 但是不行。
只需要重复百分号: %%。
\%不行, 因为反斜杠\ 是编译器的转义字符, 而这里我们的问题最终是printf的转义字符。
4.我如何用printf 实现可变的域宽度?就是说, 我想在运行时确定宽
度而不是使用%8d?
printf("%*d", width, x) 就能达到你的要求。
7).scanf函数:
1.当我用“%d\n” 调用scanf 从键盘读取数字的时候, 好像要多输入一行函数才返回。
可能令人吃惊, \n在scanf 格式串中不表示等待换行符, 而是读取并放弃所有的空白字符。
2.我用scanf %d 读取一个数字, 然后再用gets() 读取字符串, 但是
编译器好像跳过了gets() 调用!
scanf %d 不处理结尾的换行符。如果输入的数字后边紧接着一个换行符, 则
换行符会被gets() 处理。
作为一个一般规则, 你不能混用scanf() 和gets(), 或任何其它的输入例程的调
用; scanf 对换行符的特殊处理几乎一定会带来问题。要么就用scanf() 处理所有的
输入, 要么干脆不用。
3..我发现如果坚持检查返回值以确保用户输入的是我期待的数值, 则
scanf() 的使用会安全很多, 但有的时候好像会陷入无限循环。
在scanf() 转换数字的时候, 它遇到的任何非数字字符都会终止转换并被保留
在输入流中。因此, 除非采用了其它的步骤, 那么未预料到的非数字输入会不断
“阻塞” scanf(): scanf() 永远都不能越过错误的非数字字符而处理后边的合法数字
字符。如果用户在数字格式的scanf 如%d 或%f 中输入字符‘x’, 那么提示后并用
同样的scanf() 调用重试的代码会立即遇到同一个’x’。
4.为什么大家都说不要使用scanf()?那我该用什么来代替呢?
scanf() 有很多问题。而且, 它的%s 格式有着和gets() 一样的问题,很难保证接收缓冲不溢出。更一般地讲, scanf() 的设计使用于相对结构化的, 格式整齐的输入。设计上,它的名称就是来自于“scan formatted”。如果你注意到, 它会告诉你成功或失败,但它只能提供失败的大略位置, 至于失败的原因, 就无从得知了。对scanf() 的错误恢复几乎是不可能的; 通常先用类似fgets() 的函数读入整行, 然后再用sscanf() 或其它技术解释。strtol(), strtok() 和atoi() 等函数通常有用;如果你真的要用任何scanf 的变体, 你要确保检查返回值, 以确定找到了期待的值。而使用%s 格式的时候, 一定要小心缓冲区溢出。
8).&i是常量表达式
全局变量只能用常量表达式初始化,如果定义int p = i;就错了,因为i不是常量表达式,然而用i的地址来初始化一个指针却没有错,因为i的地址是在编译链接时能确定的,而不需要到运行时才知道,&i是常量表达式。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics