我无法显示循环输出的内容,我是对此的初学者。应该检查输入是字母还是数字并将其存储为标识符,如果运算符将其存储为符号并检查输入中是否包含关键字。
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void keyword(char str[10])
{
if(strcmp("for",str)==0||strcmp("while",str)==0||strcmp("do",str)==0||strcmp("int",str)==0||strcmp("float",str)==0||strcmp("char",str)==0||strcmp("double",str)==0||strcmp("static",str)==0||strcmp("switch",str)==0||strcmp("case",str)==0)
printf("\n%s is a keyword",str);
else
printf("\n%s is an identifier",str);
}
main()
{
FILE *f1,*f2,*f3;
char c,str[10],st1[10];
int num[100], lineo=0,tokenvalue=0,i=0,j=0,k=0;
printf("\nEnter the c program ");
gets(st1);
f1=fopen("input","w");
while((c=getchar())!=EOF)
putc(c,f1);
fclose(f1);
f1=fopen("input","r");
f2=fopen("identifier","w");
f3=fopen("specialchar","w");
while((c=getc(f1))!=EOF)
{
if(isdigit(c))
{
tokenvalue=c-'0';
c=getc(f1);
while(isdigit(c))
{
tokenvalue*=10+c-'0';
c=getc(f1);
}
num[i++]=tokenvalue;
ungetc(c,f1);
}
else if(isalpha(c))
{
putc(c,f2);
c=getc(f1);
while(isdigit(c)||isalpha(c)||c=='_'||c=='$')
{
putc(c,f2);
c=getc(f1);
}
putc(c,f2);
ungetc(c,f1);
}
else if(c==' '||c=='\t')
printf("");
else if(c=='\n')
lineo++;
else
putc(c,f3);
}
fclose(f2);
fclose(f3);
fclose(f1);
printf("\nThe no. im the program are");
for(j=0;j<i;j++)
printf("%d",num[j]);
printf("\n");
f2=fopen("identifier","r");
k=0;
printf("The keywords and identifiers are: ");
while((c=getc(f2))!=EOF)
{
if(c!='\0')
str[k++]=c;
else
{
str[k]='\0';
keyword(str);
k=0;
}
}
fclose(f2);
f3=fopen("specialchar","r");
printf("\nSpecial Characters are: ");
while((c=getc(f3))!=EOF)
printf("%c",c);
printf("\n");
fclose(f3);
printf("Total no. of lines are:%d",lineo);
}
最佳答案
在整个代码中,存在很多语法上的细微误用。我试图找出所有问题,并在注释中注明问题的性质。
从总体上看,但是最大的缺点是无法验证文件操作。您必须验证fopen
成功--在尝试从中读取字符之前。写入文件后,fclose
也是这样,以确保在更近的位置上不存在流错误,这将使字符不被写入文件。 (如果您只是从文件中读取,则通常不保证关闭时进行验证。)
声明字符数组以容纳字符串时,应使用0
初始化所有元素(有效地用nul终止字符填充数组,以确保您的字符串始终以nul终止,只要您不写超出数组末尾它很简单而且很短,只需要char str[10] = "", st1[10] = "";
即可(根据惯例,如果您用值填充数组或结构的第一个元素,则默认情况下所有其他元素都初始化为zero
。)
还有其他一些细微之处。您将getc
和fgetc
混合在一起。尽管可以正常工作,但是请注意,通常将getc
实现为宏,并且不能保证fgetc
可以进行单遍操作。
大致就是概述,浏览代码,然后打开代码。您可能会认为所有代码挤在一起都是可读的,但是如果您考虑到代码块之间的空白行(采用与编写段落相同的方式),则肯定会简化两者的流程。
放在一起,您可以执行以下操作:
注意:根据您的评论进行编辑,纠正了最初未解决的读取逻辑错误。
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* use constants, not 'magic numbers' in code */
enum { MAXC = 10, MAXND = 100, MAXFN = 4096 };
void keyword (char *str)
{
if (strncmp ("for", str, strlen ("for")) == 0 ||
strncmp ("while", str, strlen ("while")) == 0 ||
strncmp ("do", str, strlen ("do")) == 0 ||
strncmp ("int", str, strlen ("int")) == 0 ||
strncmp ("float", str, strlen ("float")) == 0 ||
strncmp ("char", str, strlen ("char")) == 0 ||
strncmp ("double", str, strlen ("double")) == 0 ||
strncmp ("static", str, strlen ("static")) == 0 ||
strncmp ("switch", str, strlen ("switch")) == 0 ||
strncmp ("case", str, strlen ("case")) == 0)
printf (" keyword : %s\n", str);
else
printf (" identifier : %s\n", str);
}
int main (void) /* main() is type int, and returns a value */
{
FILE *f1, *f2, *f3;
char str[MAXC] = "", st1[MAXFN] = ""; /* initialize arrays 0 */
int c, num[MAXND] = {0}, lineo = 0, tokenvalue = 0, i = 0, j = 0, k = 0;
printf ("\nEnter the c program: ");
if (!fgets (st1, 10, stdin)) {
fprintf (stderr, "error: invalid input 'st1'\n");
return 1;
}
if (!(f2 = fopen ("input", "w"))) { /* validate opening */
fprintf (stderr, "error: file open failed 'input'.\n");
return 1;
}
/* The while takes input from stdin and writes to f1, but has nothing
* to do with the file you opened "input". I'm guessing you want to
* read file stream f1 (copy it) into "input" so you can reopen it
* in "r" mode and check for identifiers, keywords, etc.
*
* You cannot redirect a file to your code, and then prompt for
* a filename -- fgets will take the code as your filename
* (or as much will fit) because stdin is FIFO, not LIFO
*
while ((c = getchar ()) != '\n' && c != EOF)
fputc (c, f1);
*/
if (!(f1 = fopen (st1, "r"))) { /* validate opening */
fprintf (stderr, "error: file open failed '%s'.\n", st1);
return 1;
}
while ((c = fgetc (f1)) != EOF) /* you should really do this with fgets */
fputc (c, f2); /* and read/write a line at a time */
fclose (f1);
if (fclose (f2)) { /* validate close after *write*, stream error */
fprintf (stderr, "error: on stream close after write 'f2'.\n");
return 1;
}
if (!(f1 = fopen ("input", "r"))) { /* validate opening */
fprintf (stderr, "error: invalid input 'input'\n");
return 1;
}
if (!(f2 = fopen ("identifier", "w"))) { /* validate opening */
fprintf (stderr, "error: invalid input 'identifier'\n");
return 1;
}
if (!(f3 = fopen ("specialchar", "w"))) { /* validate opening */
fprintf (stderr, "error: invalid input 'specialchar'\n");
return 1;
}
while ((c = fgetc (f1)) != EOF) {
if (isdigit (c)) {
tokenvalue = c - '0';
c = fgetc (f1); /* fgetc guarantees single evaluation */
while (isdigit (c)) {
tokenvalue *= 10 + c - '0';
c = fgetc (f1);
}
num[i++] = tokenvalue;
ungetc (c, f1);
} else if (isalpha (c)) {
fputc (c, f2);
if ((c = fgetc (f1)) && c != EOF) /* need () around assignment */
while (isdigit (c) || isalpha (c) || c == '_' || c == '$') {
putc (c, f2);
c = fgetc (f1);
}
fputc (c, f2);
ungetc (c, f1);
} else if (c == ' ' || c == '\t') /* one 'space' for a char */
putchar (' '); /* printing empty-char ?, looks like 'space' or 0 */
else if (c == '\n')
lineo++;
else
putc (c, f3);
}
if (fclose (f2)) { /* validate close after *write*, stream error */
fprintf (stderr, "error: on stream close after write 'f2'.\n");
return 1;
}
if (fclose (f3)) { /* validate close after *write*, stream error */
fprintf (stderr, "error: on stream close after write 'f3'.\n");
return 1;
}
fclose (f1);
printf ("\nThe nm. in the program are: ");
for (j = 0; j < i; j++)
printf ("%d", num[j]);
putchar ('\n'); /* no need for printf for a single 'char' */
if (!(f2 = fopen ("identifier", "r"))) { /* validate opening */
fprintf (stderr, "error: invalid input 'identifier'\n");
return 1;
}
k = 0;
printf ("The keywords and identifiers are: ");
while ((c = fgetc (f2)) != EOF) {
if (k + 1 < MAXC && c != '\0') /* you must limit chars to str len */
str[k++] = c; /* and your logic needs a rework */
else {
str[k] = 0;
keyword (str);
k = 0;
}
}
putchar ('\n');
fclose (f2);
if (!(f3 = fopen ("specialchar", "r"))) { /* validate opening */
fprintf (stderr, "error: invalid input 'specialchar'\n");
return 1;
}
printf ("\nSpecial Characters are: ");
while ((c = getc (f3)) != EOF)
printf ("%c", c);
putchar ('\n');
fclose (f3);
printf ("Total no. of lines are: %d\n", lineo);
}
我已经运行了一个简短的C文件来测试您的逻辑。您仍有一些工作要做。编译它并运行您的数据,如果还有其他问题,请告诉我。一个显示您仍有工作要做的示例:
输入文件
$ nl -ba whileit.c
1 #include <stdio.h>
2 #include <string.h>
3
4 int main (void) {
5
6 char a[] = "You are welcome",
7 b[5][20] = {{0}},
8 *pch;
9 int i = 0;
10
11 pch = strtok ( a," \t" );
12
13 while (i < 5 && pch) {
14 strcpy (b[i++], pch);
15 pch = strtok( NULL, " \t\n" );
16 }
17
18 i = 0;
19 while (*b[i]) {
20 printf( "b[%d] = %s\n", i, b[i] );
21 i++;
22 }
23
24 return 0;
25 }
使用/输出示例
$ ./bin/fopenprob
Enter the c program: whileit.c
The nm. in the program are: 52000500 // nm is correct
The keywords and identifiers are: identifier : include s
identifier : dio.h>inc
identifier : ude strin
identifier : .h>int ma
identifier : n void)ch
identifier : r a[You a
identifier : e welcome
identifier : b[pch;int
identifier : i pch str // keyword logic needs work
identifier : ok a,t"wh
identifier : le i pch)
identifier : trcpy b[i
identifier : pch)pch s
identifier : rtok(NULL
identifier : t\n"i whi
identifier : e b[i]pri
identifier : tf(b[d]s\
identifier : "i,b[i]i+
Special Characters are: #<.>#<.>(){[]="",[][]={{}},*;=;=(,"\");(<&&){([++],);=(,"\\");}=;(*[]){("[%]=%\",,[]);++;};}
Total no. of lines are: 25
书面文件
$ nl -ba input
1 #include <stdio.h>
2 #include <string.h>
3
4 int main (void) {
5
6 char a[] = "You are welcome",
7 b[5][20] = {{0}},
8 *pch;
9 int i = 0;
10
11 pch = strtok ( a," \t" );
12
13 while (i < 5 && pch) {
14 strcpy (b[i++], pch);
15 pch = strtok( NULL, " \t\n" );
16 }
17
18 i = 0;
19 while (*b[i]) {
20 printf( "b[%d] = %s\n", i, b[i] );
21 i++;
22 }
23
24 return 0;
25 }
(为了便于阅读,手动换行符为79个字符-文件中没有:)
$ cat identifier
include stdio.h>include string.h>int main void)char a[You are welcome"b[pch;int
i pch strtok a,t"while i pch)strcpy b[i+pch)pch strtok(NULL,t\n"i while b[i]pri
ntf(b[d]s\n"i,b[i]i+return
$ cat specialchar
#<.>#<.>(){[]="",[][]={{}},*;=;=(,"\");(<&&){([++],);=(,"\\");}=;(*[]){("[%]=%\
",,[]);++;};}
如您所见,关键字和标识符逻辑需要工作。提示,要识别关键字和标识符,您必须确保仅将以标识符开头的字符串发送到
keyword
函数。我已修改您的keyword
函数以使用strncmp
测试关键字,因此您可以发送例如"for(i=0"
到keyword
,它将标识"for"
,但是必须确保str
以关键字开头。我还在您的代码中留下了其他注释以进行改进。这应该足以让您继续前进,而不必“为您做” :)
关于c - 如何显示不循环输出的输出?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38842868/