在out[0] = '\0';函数上使用main()的原因是什么?
如果没有它,它似乎确实起作用。
码
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXTOKEN 100
enum { NAME, PARENS, BRACKETS };
int tokentype;
char token[MAXTOKEN]; /*last token string */
char name[MAXTOKEN]; /*identifier name */
char datatype[MAXTOKEN]; /*data type = char, int, etc. */
char out[1000];
void dcl(void);
void dirdcl(void);
int gettoken(void);
/*
Grammar:
dcl: optional * direct-dcl
direct-dcl: name
(dcl)
direct-dcl()
direct-dcl[optional size]
*/
int main() /* convert declaration to words */
{
while (gettoken() != EOF) { /* 1st token on line */
/* 1. gettoken() gets the datatype from the token */
strcpy(datatype, token);
/* 2. Init out to end of the line? */
/* out[0] = '\0'; */
/* parse rest of line */
dcl();
if (tokentype != '\n')
printf("syntax error\n");
printf("%s: %s %s\n", name, out, datatype);
}
return 0;
}
int gettoken(void) /* return next token */
{
int c, getch(void);
void ungetch(int);
char *p = token;
/* Skip blank spaces and tabs */
while ((c = getch()) == ' ' || c == '\t')
;
if (c == '(') {
if ((c = getch()) == ')') {
strcpy(token, "()");
return tokentype = PARENS;
} else {
ungetch(c);
return tokentype = '(';
}
} else if (c == '[') {
for (*p++ = c; (*p++ = getch()) != ']'; )
;
*p = '\0';
return tokentype = BRACKETS;
} else if (isalpha(c)) {
/* Reads the next character of input */
for (*p++ = c; isalnum(c = getch()); ) {
*p++ = c;
}
*p = '\0';
ungetch(c); /* Get back the space, tab */
return tokentype = NAME;
} else
return tokentype = c;
}
/* dcl: parse a declarator */
void dcl(void)
{
int ns;
for (ns = 0; gettoken() == '*'; ) /* count *'s */
ns++;
dirdcl();
while (ns-- > 0)
strcat(out, " pointer to");
}
/* dirdcl: parse a direct declarator */
void dirdcl(void)
{
int type;
if (tokentype == '(') {
dcl();
if (tokentype != ')')
printf("error: missing )\n");
}
else if (tokentype == NAME) /* variable name */ {
strcpy(name, token);
printf("token: %s\n", token);
}
else
printf("error: expected name or (dcl)\n");
while ((type = gettoken()) == PARENS || type == BRACKETS) {
if (type == PARENS)
strcat(out, " function returning");
else {
strcat(out, " array");
strcat(out, token);
strcat(out, " of");
}
}
}发布于 2016-11-02 19:37:07
您需要out[0]为零才能使strcat工作。
而这条线
out[0] = '\0';在引入静态初始化规则之前是必需的,因此不再需要它,因为静态数组(如out[] )被初始化为所有零。
据initialization rules of C99称,
发布于 2016-11-02 19:41:14
它正在将char数组(也称为字符串)重置为空数组。(删除垃圾值)就像我们使用的那样:
int i = 0;在做以下事情之前:
i += 1;这样垃圾价值就不会增加
因此,只有数组的0索引中的'\0‘表示数组是完全空的,strcat函数从0索引开始追加值,在数组的其他索引中写入垃圾值。
如果程序在没有重置数组的情况下工作,那么它就意味着IDE工具正在为您做这件事,但是重新设置它是很好的做法。
发布于 2016-11-02 20:40:10
简而言之:在这种特殊情况下,这并不是绝对必要的,但在其他看起来很相似的情况下,它确实是必要的,所以大多数人都把它当作“好风格”。那为什么有这个必要呢?
没有所谓的“空”记忆。没有“长度”这样的东西。除非您显式地跟踪它,或者定义您自己的。
内存只是字节,是0到255之间的数字。由于0与255一样有效,因此无法判断是否使用了字节。如果你需要更大的数字,你可以“加”几个字节,但是最终,所有的东西都是由字节构成的。文本被简单地映射到一个数字。二十年前,人们决定哪个数字代表哪个字符。所以如果你看到一个32值的字节,它可能是32。也可以是计算机字母表中的第32个字母(这是空格字符)。
当您收到一个字符串,而您不知道要处理多少文本时,通常所做的是保留一个大字节块。这就是上面char out[1000];所做的。但是你怎么知道文本的结尾呢?您已经使用过的1000个字节中有多少?
好吧,在过去,有些人只会声明另一个变量,比如int length;,并跟踪到目前为止他们使用了多少字节。C的设计者走了一条不同的路线。他们决定挑选一个非常罕见的字符,并以此作为标记。他们选择了值为0的字符(这不是字符'0‘)。字符'0‘实际上是计算机字母表的第48个字母)。
因此,您可以从一开始就查看字符串中的所有字节,如果一个字符> 0,您就知道它是使用的。如果到达0字符,则知道这是字符串的结尾。这两种方法都有各种好处。int只使用4个字节,另外一个0-字符仅为1。另一方面,如果使用int,字符串也可以包含0-字符,这只是另一个字符,没有人关心。
每当您用C编写"foo"时,C实际上所做的是为'f'、'o'、'o'和0预留4个字节的空间以指示结束。当您用C编写""时,它所做的是为单个字节( 0 )预留空间。这样你就可以知道字符串是空的。
那么,在启动之前,内存中装满了什么呢?嗯,在大多数情况下,这只是垃圾。不管上次使用内存是什么(毕竟,你的内存有限,所以当你退出计算机上的一个应用程序时,它的内存就可以在你启动的下一个应用程序中重新使用)。这些都是随机数,往往超出了普通字符的范围。
因此,如果希望strcat将out视为空字符串,则需要给它一个以0值字符开头的内存块。如果你只留下这样的记忆,里面可能会有一些随机字符。您的缓冲区可能包含"jbhasugaudq7e1723876123798dbkda0skno§§^^%$#-9H0HWDZmwus0/usr/local/bin“或以前在该内存中的任何内容。如果您现在附加了一些文本,它会认为第一个0之前的内容(在这里只是随机的)是一个有效的字符串,并将其附加到该字符串中。只有当您将0放在开头时,它才会知道这个字符串应该是空的。
那为何我说这是“绝对没有必要”呢?因为在您的示例中,out是一个全局变量,而全局变量是特殊的,因为它们在应用程序启动时自动被清除为0(或者在声明它们时分配给它们的任何值)。
但是,这只适用于全局变量(常规全局变量和static全局变量)。很多程序员习惯于总是初始化他们的字节块。这样,如果某个人后来决定将全局变量更改为局部变量,或者将代码复制并粘贴到另一个位置以便与局部变量一起使用,那么他们不必担心忘记添加这个语句。
这特别有用,因为随机内存通常包含0字符。因此,根据您以前使用的程序,您可能不会注意到您忘记了初始的0,因为其中碰巧已经有一个了。直到稍后,当您的一个用户运行这个应用程序时,他们才会在字符串开始时收到垃圾。
这能澄清一些事情吗?
https://stackoverflow.com/questions/40388241
复制相似问题