星号在printf中主要有两种作用,一种是确定域宽(说白了就是你希望给这个变量输出用多少字符,不足的会用空格填充),另一种是浮点数输出精度控制,都允许传变量。
A问题很简单,C语言字符串必须用双引号包住,那么想在双引号里边包含一个双引号的话,就需要转义(escape)。转义在计算机领域广泛存在,不过不同环境的转义语法往往不同。最常见的是URL转义(但几乎只能在网页环境下见到)和类似C语言的*nix转义(几乎能在任何本地应用中见到,不仅是C语言,也不仅是程序设计)。
对于B和C,先举例说明啥是域宽。格式控制串(就是scanf和printf中的第一个参数,不过要注意scanf和printf中同一格式串的含义肯定是不同的)的每个百分号对应一个要输出的东西,每一个被称为一个域(field)。域的宽度一般与数据本身输出长度等同,例如printf("%d", 123)中只有一个域,这个域的域宽是三个字节,正好是十进制整数123的长度。但有时我们希望输出类似表格的东西,我们会希望让一位数、两位数、三位数都能对齐,而且数字之间至少有一个空格,而不是乱七八糟一堆。就像这样:
这固然可以通过循环实现,但是太麻烦,printf提供的简便方法是:我们可以直接让每个数位宽为4(每个数有至少一个前置空格,就足以保证两两之间有空格分开)。这样,希望输出1时,printf会自动加上3个空格,以保证和下一行的两位数或三位数保持对齐。
域中可以规定是左对齐还是右对齐。希望右对齐的话,域宽指定为正数就可以。希望左对齐就指定为负数。
当要输出的数据宽度大于域宽时,域宽设置会被忽视,不会产生报错。
因此,假定你输入的name为abc(三个字符),B问题中,你给出了正值域宽,这个域将会右对齐,输出效果是:先是引号,然后17个空格,然是abc,最后还有一个引号。C问题中,你给出的域宽为负值,这个域会左对齐(和你的注释中一样),输出则是先是引号,然后是abc,接下来是17个空格,最后是另一个引号。
D问题涉及星号。星号允许用变量控制域宽,例如,printf("%*d*%*d", 2, 5, -4, 3)中,格式串最先遇到一个百分号后紧跟的星号(显然,如果星号没和百分号在一起,将会原样输出),第一个参数2会被匹配到这。第二个是百分号紧随的d,第二个参数5匹配到这来。接下来遇到了一个星号,但由于跟变量/输出域没关系,将会原样输出。然后又是百分号,跟它有关的星号和d分别匹配到-4和3。所以输出是这样的:
(一个空格)5*3(3个空格)
值得注意的是你的程序有一个看起来似乎是bug的东西:从上下文来看,name最长为20字符,但长度为20的char数组最多只能安全地存放19个。你可能注意到了,实际尝试一下很可能不出问题,但是运气好的时候哪怕填三十个字符也可能不出错,这纯粹是运气好而已。C的字符串有个NULL-terminator,占用一个字符,因此,要安全存放最长20字符的数据,至少需要长度为21的字符数组。