C语言入门——hello world

November 6, 2018 · 再学C · 2次阅读

写在前面,因为电脑之前装过VS 2015了,虽然一直没有怎么用,不过打开软件写代码还是有点耗费资源,正当纠结选哪个编译器的时候,突然想起有命令行编译的工具cl,那就用cl吧~~~
tips:要在屏幕上打印文字。比如下面的hello world,要么加上注释那句,要么在命令行直接执行exe,就能看到效果了~


第一个C语言程序:

#include <stdio.h>

main()
{
    printf("hello, world !\n");
    // system("pause");
}

Q:有意去掉部分内容,会得到什么出错信息?
A:无法编译(当然也可能编译通过但是执行没有任何信息显示),比如printf——>pritf,编译结果如下图:
QQ截图20181106201449.png
Q:做个实验,当printf函数参数字符串中包含c时,观察一下会出现什么情况?
A:编译提示helloworld.c(5): warning C4129: “c”: 不可识别的字符转义序列,执行程序还是有个c。
QQ截图20181106202105.png

Q:修改温度转换程序,使之能在转换表的顶部打印一个标题。
A:如图:QQ截图20181106204144.png

#include <stdio.h>

main()
{
    float fahr, celsius;
    int lower, upper, step;
    lower = 0;
    upper = 300;
    step = 20;
    fahr = lower;
    printf("fahr celsius generate\n");
    while (fahr <= upper) {
        celsius = (5.0 / 9.0) * (fahr - 32);
        printf("%6.0f  %6.1f\n", fahr, celsius);
        fahr = fahr + step;
        }
    // system("pause");
}

Q:编写一个程序打印摄氏温度转换相应华氏温度的转换表。
A:代码如下:
QQ截图20181106204708.png

#include <stdio.h>

main()
{
    float fahr, celsius;
    int lower, upper, step;
    lower = 0;
    upper = 150;
    step = 10;
    celsius = lower;
    printf("celsius fahr generate\n");
    while (celsius <= upper) {
        fahr = (celsius * 9.0) / 5.0 + 32;
        printf("%6.0f  %6.1f\n", celsius, fahr);
        celsius = celsius + step;
        }
    // system("pause");
}

Q:修改温度转换程序,要求以逆序打印温度转换表。
A:代码如下:
QQ截图20181106205856.png

#include <stdio.h>

main()
{
    int fahr;
    printf("celsius fahr generate\n");
    for (fahr = 300; fahr >= 0; fahr = fahr - 20)
        printf("%6d  %6.1f\n", fahr, (5.0 / 9.0) * (fahr - 32));
    // system("pause");
}

Q:打印EOF的值。
A:在主程序中使用printf("%d\n", EOF);打印,结果为-1。
Q:验证表达式getchar() != EOF的值是0还是1。
A:代码如下,通过输入验证,该表达式的值在成立的条件下为1

#include <stdio.h>

main()
{
    int char_in;
    char_in = (getchar() != EOF);
    printf("%d\n", char_in);
}

Q:编写一个统计空格、制表符与换行个数的程序。
A:代码如下:

#include <stdio.h>

main()
{
    char char_in;
    int num_s,num_t,num_e;//空格、制表符、换行符
    num_s = 0;
    num_t = 0;
    num_e = 0;
    char_in = getchar();
    while (char_in != EOF){
        if (char_in == ' ')
            num_s++;
        if (char_in == '\t')
            num_t++;
        if (char_in == '\n')//每次输入时都会回车,所以通过回车将字符送入时,送入的字符包括了回车/换行
            num_e++;
        putchar(char_in);
        char_in = getchar();
    }
    printf("%d %d %d", num_s, num_t, num_e);
}

Q:编写一个将输入复制到输出的程序,并将其中连续的多个空格用一个空格代替。
A:代码如下:

#include <stdio.h>

main()
{
    char char_in[100],char_out[100];
    int i, j;
    j = 0;
    puts("input your string:\n");
    gets(char_in);
    for (i = 0; i <= strlen(char_in); i++)
    {
        if ((char_in[i] == ' ') && (char_out[j-1] == ' '))
            continue;
        char_out[j] = char_in[i];
        j++;
    }
    printf("%s", char_out);
}

运行示例:

>helloworld.exe
input your string:

hi  my name is wm, what   is your name?
hi my name is wm, what is your name?

Q:编写一个将输入复制到输出的程序,并将其中的制表符换成t,把回退符换成b,把反斜杠换成\。这样可以将制表符和回退符以可见的方式显示出来。
A:注意,代码中使用的是gets,输入回退符实际不起作用,因为它是在回车之后读取的,实际上回退符会删除字符,并且不会处理回车输入的回车符。要处理可以用getch(需要引入头文件conio.h)。

#include <stdio.h>

main()
{
    char char_in[100],char_out[100];
    int i, j;
    j = 0;
    puts("input your string:\n");
    gets(char_in);
    for (i = 0; i <= strlen(char_in); i++)
    {
        if (char_in[i] == '\t')
        {
            char_out[j++] = '\\';
            char_out[j++] = 't';
            continue;
        }
        if (char_in[i] == '\b')
        {
            char_out[j++] = '\\';
            char_out[j++] = 'b';
            continue;
        }
        if (char_in[i] == '/')
        {
            char_out[j++] = '\\';
            continue;
        }
        char_out[j++] = char_in[i];
    }
    printf("%s", char_out);
}

Q:你准备如何测试单词计数程序?如果程序中存在某种错误,那什么样的输入最可能发现这类错误呢?
A:代码如下,编译后执行输入测试呗。有可能存在的情况是,比如输入的字符中包括类EOF的字符,然后程序提前结束了。

#include <stdio.h>
#include <conio.h>

#define IN 1
#define OUT 0

main()
{
    int c, n1, nw, nc, state;
    
    state = OUT;
    n1 = nw = nc = 0;
    while ((c = getchar()) != EOF)
    {
        ++nc;
        if (c == '\n')
            ++n1;
        if (c == ' ' || c == '\n' || c == '\t')
            state = OUT;
        else if (state == OUT)
        {
            state = IN;
            ++nw;
        }
    }
    printf("%d %d %d\n", n1, nw, nc);
}

测试示例(Ctrl Z结束输入):

>helloworld.exe
my name is wang




^Z
5 4 20

Q:编写一个程序,以每行一个单词的形式打印其输出。
A:代码如下,对比了下最好的答案,错在思路上?

#include <stdio.h>
#include <string.h>

main()
{
    int i=0, j=0;
    char char_out[5][10]={"","","","",""};
    char char_temp[10];
    char c;
    while ((c = getchar()) != EOF)
    {
        if (c == '\n')
        {
            strcpy(char_out[j],char_temp);
            break;
        }
        else//不用else的话 在回车输入的时候就会把回车放到字符串
            char_temp[i++] = c;
        if (c == ' ' || c == '\t')
        {
            char_temp[i] = 0;//这个时候已经包含了空格,需要去掉
            strcpy(char_out[j],char_temp);
            // strcpy(char_temp,"");
            // char_temp[0] = 0;
            memset(char_temp, 0 , sizeof(char_temp));
            i = 0;
            j++;
        }
    }
    i = 0;
    for (i = 0; i <= 4; i++)
    {
        printf("%s\n", char_out[i]);
    }
    
}

较标准答案:

#include <stdio.h>
#define IN 1
#define OUT 0

int main()
{
    int c, state;
    state = OUT;
    while( (c = getchar()) != EOF)
    {
        if(c == ' ' || c == '\n' || c == '\t')
        {
            if(state == IN)
            {
                putchar('\n');
                state = OUT;
            }
        }
        else if (state == OUT)
        {
            state = IN;
            putchar(c);
        }
        else
            putchar(c);
    }
}

Q:编写一个程序,打印输入中各个字符出现频度的直方图。
A:代码如下,就是对字符做统计,可以参考书本的例子,稍作改变即可实现

#include <stdio.h>

print_same(int num)
{
    int i;
    for (i = 0; i < num; i++)
        printf("-*");
    printf("\n");
}

main()
{
    int c, i, nother = 0;
    int nletter[26];
    for (i = 0; i < 26; i++)
        nletter[i] = 0;
    
    while((c = getchar()) != '\n')
        if (c >= 'a' && c <= 'z')
            ++nletter[c - 'a'];
        else if (c >= 'A' && c <= 'Z')
            ++nletter[c - 'A'];
        else
            ++nother;
    for (i = 0;i < 26; i++)
    {
        printf("%c ", (65 + i));
        if (nletter[i] == 0)
            printf("\n");
        else
            print_same(nletter[i]);
    }
    
}

执行示例:

>helloworld.exe
hello, my name is li hua.you can see that i am very love this car. its beautiful and cool. i think you will love it too.
A -*-*-*-*-*-*-*-*
B -*
C -*-*-*
D -*
E -*-*-*-*-*-*-*-*
F -*
G
H -*-*-*-*-*
I -*-*-*-*-*-*-*-*-*-*
J
K -*
L -*-*-*-*-*-*-*-*-*
M -*-*-*
N -*-*-*-*
O -*-*-*-*-*-*-*-*-*
P
Q
R -*-*
S -*-*-*-*
T -*-*-*-*-*-*-*-*
U -*-*-*-*-*
V -*-*-*
W -*
X
Y -*-*-*-*
Z

Q:编写一个程序,打印输入中单词长度的直方图,水平的直方图比垂直的直方图简单。
A:主要是巧妙处理费字母字符以及连续的非字母字符出现情况。代码如下:

#include <stdio.h>

print_same(int num)
{
    int i;
    for (i = 0; i < num; i++)
        printf("-*");
    printf("\n");
}

main()
{
    int c, i, n, flag;
    int nletter[100];
    n = flag = 0;
    for (i = 0; i < 100; i++)
        nletter[i] = 0;
    i = 0;
    while((c = getchar()) != '\n')
    {
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
            i++;
        else
        {
            if (i == 0)
                continue;
            nletter[n] = i;
            n++;
            i = 0;
        }
    }
    i = 0;
    while(nletter[i] != 0)
    {
        printf("%d ", nletter[i]);
        print_same(nletter[i]);
        i++;
    }
    
}

执行示例:

>helloworld.exe
hello, my name is li hua.you can see that i am very love this car. its beautiful and cool. i think you will love it too.
5 -*-*-*-*-*
2 -*-*
4 -*-*-*-*
2 -*-*
2 -*-*
3 -*-*-*
3 -*-*-*
3 -*-*-*
3 -*-*-*
4 -*-*-*-*
1 -*
2 -*-*
4 -*-*-*-*
4 -*-*-*-*
4 -*-*-*-*
3 -*-*-*
3 -*-*-*
9 -*-*-*-*-*-*-*-*-*
3 -*-*-*
4 -*-*-*-*
1 -*
5 -*-*-*-*-*
3 -*-*-*
4 -*-*-*-*
4 -*-*-*-*
2 -*-*
3 -*-*-*

C语言函数结构:

返回值类型 函数名(0个或多个参数声明)
{
    声明部分
    语句序列
}

通常把函数定义中圆括号内列表中出现的变量称为形式参数,而把函数调用中形式参数对应的值称为实际参数。
Q:修改温度转换程序,使用函数实现温度转换计算
A:代码如下

#include <stdio.h>

main()
{
    float fahr, celsius;
    int lower, upper, step;
    float f2c(float fahr);//声明函数
    lower = 0;
    upper = 300;
    step = 20;
    fahr = lower;
    printf("fahr celsius generate\n");
    while (fahr <= upper) {
        celsius = f2c(fahr);
        printf("%6.0f  %6.1f\n", fahr, celsius);
        fahr = fahr + step;
        }
}

float f2c(float fahr)
{
    float celsius; 
    celsius = (5.0 / 9.0) * (fahr - 32);
    return celsius;
}

Q:修改打印最长文本行的程序的主程序main,使之可以打印任意长度的输入行的长度,并尽可能多的打印文本。
A:修改后的代码如下,说明:去除了输入字符的限制,最多10个字符,其中最后两位用于存放换行和0结束标志。问题,如果在一行中输入EOF(比如 Ctrl Z),那么会继续输入计数,正常的结束时在一行换行结束此行输入后输入EOF(Ctrl Z),然后再Ctrl Z问题已解决,方法是EOF、换行等直接写入零结束标志

#include <stdio.h>
#define MAXLINE 10

int getline(char line[], int maxline);
void copy(char to[], char from[]);

/* 打印最长的输入行 */
main()
{
    int len;/* 当前的行长度 */
    int max;/* 目前为止发现的最长行长度 */
    char line[MAXLINE];/* 当前的输入行 */
    char longest[MAXLINE];/* 用于保存最长的行 */
    
    max = 0;
    while ((len = getline(line, MAXLINE)) > 0){
        printf("the length of this line is %d.\n", len);
        if (len > max){
            max = len;
            copy(longest, line);
    }}
    if (max > 0)
        printf("%s", longest);/* 存在这样的行 */
    return 0;
}

/* getline函数:将一行读入到s并返回其长度 */
int getline(char s[], int lim)
{
    int c, i;
    
    for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c!= '\n'; ++i)
        s[i] = c;
    if (c == '\n' || c == EOF){
        s[i] = '\0';
    }
    else
    {
        s[i] = '\0';
        while ((c = getchar()) != '\n' && i != 0)
            ++i;
    }
    return i;
}

/* copy函数:将from复制到to;这里假定to足够大 */
void copy(char to[], char from[])
{
    int i;
    
    i = 0;
    while ((to[i] = from[i]) != '\0')
        ++i;
}

Q:编写一个程序,打印长度大于80的所有输入行
A:代码在上一个函数中修改main函数即可,这里测试大于15即可,main函数代码如下:

main()
{
    int len;/* 当前的行长度 */
    char line[MAXLINE];/* 当前的输入行 */
    char longest[MAXLINE];/* 用于保存最长的行 */
    
    while ((len = getline(line, MAXLINE)) > 0){
        printf("the length of this line is %d.\n", len);
        if (len > 15){
            printf("%s\n", line);
    }}
    return 0;
}

Q:编写一个程序,删除行末尾的制表符和空格,并删除完全是空格的行。
A:在检查到输入结束,比如换行或零结束标志作为输入完成,通过getchar向前循环判断是不是制表符或空格,用零标志替换即可,没有则末尾就是零标志。
Q:编写函数reverse(s),将字符串s中的字符顺序颠倒过来。使用该函数编写一个程序,每次颠倒一个输入行中的字符顺序。
A:代码如下,感觉我写的怪怪的

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
char *reverse(char line[], int linelen);

/* 颠倒输入行 */
main()
{
    int linelen;/* 行长度 */
    char line[MAXLINE];/* 输入行 */
    char *revline;
    
    while ((linelen = getline(line, MAXLINE)) > 0)
    {
        revline = reverse(line, linelen);
        printf("%s\n", revline);
    }
    return 0;
}

/* getline函数:将一行读入到s并返回其长度 */
int getline(char s[], int lim)
{
    int c, i;
    
    for (i = 0; i < lim - 2 && (c = getchar()) != EOF && c!= '\n'; ++i)
        s[i] = c;
    if (c == '\n' || c == EOF){
        s[i] = '\0';
    }
    else
    {
        s[i] = '\0';
        while ((c = getchar()) != '\n' && i != 0)
            ++i;
    }
    return i;//这个长度不包括末尾的换行和零标志
}

/* reverse函数:颠倒字符数组顺序 */
char *reverse(char line[], int linelen)
{
    int i;
    char revline[MAXLINE];
    
    i = 0;
    while ((linelen - i - 1) != -2)
    {
        revline[i] = line[linelen - i - 1];
        ++i;
    }
    revline[i] = '\0';
    return revline;
}

Q:编写程序detab,将输入中的制表符替换成适当数目的空格,使空格充满到下一个制表符终止位的地方。假设制表符终止位的位置是固定的,比如每隔n列就会出现一个制表符终止位。n应该作为变量还是符号常量呢?
A:一个制表符通常和四个字符(文本是这样,但命令行一个TAB是8个字符宽)一样宽,n应当是作为常量。关键在于,如果你输入了两个字符,此时你按下TAB(制表符),实际上只向后走了2个符号的位置。代码如下:

#include <stdio.h>
#define MAXLINE 1000
#define n 8

int getline(char line[], int maxline);
void detab(char s[], int len, char detab_line[]);


main()
{
    int linelen;/* 行长度 */
    char line[MAXLINE];/* 输入行 */
    char detab_line[MAXLINE];/* 结果行 */
    
    linelen = getline(line, MAXLINE);
    printf("length is %d.\n", linelen);
    detab(line, linelen, detab_line);
    printf("%s.\n", detab_line);
    return 0;
}

/* getline函数:将一行读入到s并返回其长度 */
int getline(char s[], int lim)
{
    int c, i;
    
    for (i = 0; i < lim - 2 && (c = getchar()) != EOF && c!= '\n'; ++i)
    {
        s[i] = c;
    }
    if (c == '\n' || c == EOF){
        s[i] = '\0';
    }
    else
    {
        s[i] = '\0';
        while ((c = getchar()) != '\n' && i != 0)
            ++i;
    }
    return i;//这个长度不包括末尾的换行和零标志
}

void detab(char s[], int len, char detab_line[])
{
    int i, j, num=0;
    for (i = 0; i < len; i++)
    {
        if (s[i] == '\t')
        {
            //j 需要的空格数
            for (j =0; j < n - (i % n); j++)
            {
                detab_line[num++] = ' ';
            }
        }
        else if (s[i] == '\0')
        {
            detab_line[num++] = '\0';
            break;
        }
        else
        {
            detab_line[num++] = s[i];
        }
    }
}

Q:编写程序entab,将空格串替换为最少数量的制表符和空格,但要保持单词之间的间隔不变。假设制表符终止位的位置与上一个问题的detab程序的情况相同。当使用一个制表符或者一个空格都可以到达下一个制表符终止位时,选用哪一种替换字符比较好?
A:我的理解是比如9个空格(表述不够清晰,是刚好制表符位置这样)组成的空格串,转换为一个制表符和一个空格(假设一个制表符是8个字符宽)。当然是尽量使用制表符,因为这样可以节省数组空间。关键在于空格开始的位置和空格的个数,有空格在制表符末位,即第8、16位并且向前至少1个字符是空格使用制表符才有意义。代码如下,我的方案有点绕的地方,可能有点不好理解...

#include <stdio.h>
#define MAXLINE 1000
#define n 8

int getline(char line[], int maxline);
void entab(char s[], int len, char entab_line[]);

main()
{
    int linelen;/* 行长度 */
    char line[MAXLINE];/* 输入行 */
    char entab_line[MAXLINE];/* 结果行 */
    
    linelen = getline(line, MAXLINE);
    printf("length is %d.\n", linelen);
    entab(line, linelen, entab_line);
    printf("%s.\n", entab_line);
    return 0;
}

/* getline函数:将一行读入到s并返回其长度 */
int getline(char s[], int lim)
{
    int c, i;
    
    for (i = 0; i < lim - 2 && (c = getchar()) != EOF && c!= '\n'; ++i)
    {
        s[i] = c;
    }
    if (c == '\n' || c == EOF){
        s[i] = '\0';
    }
    else
    {
        s[i] = '\0';
        while ((c = getchar()) != '\n' && i != 0)
            ++i;
    }
    return i;//这个长度不包括末尾的换行和零标志
}

void entab(char s[], int len, char entab_line[])
{
    int i, j=0, num=0;
    for (i = 0; i < len; i++)
    {
        if ((i + 1) % n == 0 && s[i] ==' ')
        {
            while(s[--i] == ' ' && j < n - 1)
            {
                entab_line[num--] = '\0';//每向前一个是空格,则在这个位置准备好用制表符替换,并将将被制表符代替的位置写0
                j++;//用于判断是不是存在向前至少2个都是空格
            }
            i = i + j + 1;
            if (j > 0)//说明至少两个空格,可以选择用一个制表符代替
            {
                entab_line[num++] = '\t';
                j = 0;
            }
        }
        else
        {
            entab_line[num++] = s[i];
        }
    }
}

Q:编写一个程序,把较长的输入行”折“成短一些的两行或多行,折行的位置在输入行的第n列之前的最后一个非空格之后。要保证程序能够智能地处理输入行很长以及在指定的列前没有空格或制表符的情况。
A:代码如下,具体说明见注释

#include <stdio.h>
#define MAXLINE 1000
#define n 8//制表符固定列数
#define goodlen 10//换行的适宜长度 可自行设置

int getline(char line[], int maxline);
void fmatcode(char s[], int len, char fmat_line[]);

main()
{
    int linelen;/* 行长度 */
    char line[MAXLINE];/* 输入行 */
    char fmat_line[MAXLINE];/* 结果行 */
    
    linelen = getline(line, MAXLINE);
    printf("length is %d.\n", linelen);
    fmatcode(line, linelen, fmat_line);
    printf("%s.\n", fmat_line);
    return 0;
}

/* getline函数:将一行读入到s并返回其长度 */
int getline(char s[], int lim)
{
    int c, i;
    
    for (i = 0; i < lim - 2 && (c = getchar()) != EOF && c!= '\n'; ++i)
    {
        s[i] = c;
    }
    if (c == '\n' || c == EOF){
        s[i] = '\0';
    }
    else
    {
        s[i] = '\0';
        while ((c = getchar()) != '\n' && i != 0)
            ++i;
    }
    return i;//这个长度不包括末尾的换行和零标志
}

//合理拆分过长行,假设一行30字符是最合理的
//思路:遍历字符数组,到第30个位置时,作一些判断。
//如果31位是空格或者制表符,那么往前挪一个单词然后折行。
//题目意思是上面这种情况直接可以折行了,但是我认为这样直接折行,
//新行开头就是空格,不美观。(划去,英文文章好像是允许空格。直接折行
//如果是单词,那么向前遍历,遇到空格就可以折行了
//还有个问题,一个制表符的宽度要考虑下,所以是按实际宽度与30对比的
void fmatcode(char s[], int len, char fmat_line[])
{
    int i, temp, j=0, num=0;
    for (i = 0; i < len; i++)
    {
        if (s[i] == '\t')
        {
            printf("检查到制表符,且j为%d.\n", j);
            j = j + n - j % n;//用于判断制表符是不是刚好在最适合折行的位置
            //当位置为24 25 26 27 28 29 30的时候,制表符占据(横跨)了折行位置,需要将其放到下一行
            if (j % goodlen > 0 && j % goodlen < n)
            {
                j = n;//制表符放到新行开始了,j置为制表符长度
                fmat_line[num++] = '\n';//插入换行符
                printf("插入换行符\n");
                // i--;
            }
            // else
            // {
                // printf("j当前值是%d.\n", j);
                // j = j + n - j % n;//j用来记显示的字符串(包含空格、制表符)的长度
                // printf("j增加一个制表符宽度后值是%d.\n", j);
            // }
            fmat_line[num++] = '\t';
            printf("插入制表符ttttt\n");
            printf("j值是%d.\n", j);
        }
        else if (++j % goodlen != 0)
        {
            printf("字符%c当前不位于换行处.\n", s[i]);
            fmat_line[num++] = s[i];
            printf("正常复制单字符%c.\n", s[i]);
        }
        else
        {
            printf("字符%c当前位于换行处.\n", s[i]);
            if (s[i] == ' ')//换行位置是空格
            {
                fmat_line[num++] = '\n';
                fmat_line[num++] = s[i];
                printf("插入换行符 新行空格\n");
            }
            else//是单词 单词横跨了换行(不考虑标点符号 要考虑可以在前面的if上加条件)
            {
                printf("换行处是单词.\n");
                printf("num是%d i是%d.\n", num, i);
                temp = fmat_line[--i];
                while (temp != ' ' && temp != '\t')//直到向前遇到空格或制表符 那么就可以换行了
                {
                    num--;
                    //将循环从新换行的单词开始
                }
                num--;//遇到空格 制表符 num还需要前移一位,空格 制表符放新行
                printf("num是%d i是%d.\n", num, i);
                fmat_line[num++] = '\n';
                i--;//空格or制表符都被换到新行了 那么循环得往前调整一个字符
                printf("插入换行符 单词新行\n");
            }
        }
    }
}

Q:编写一个删除C语言程序中所有的注释语句。要正确处理带引号的字符串与字符常量。在C语言中,注释不允许嵌套。
A:这个题想了挺久,后面还是求助了。原来是用状态机这种思想,最开始的题就已经涉及了,而且前面几个题也可以这样做,看来没有领悟到作者的用意啊~~~下面是(基本copy)基于状态机的方法。这个可以改一点,就是以整个程序输入完了再输出结果,不过得改些地方。{附上来源:https://www.cnblogs.com/zhanghaiba/p/3569928.html}

#include <stdio.h>

void delnote();

int main(void)
{
    delnote();
    return 0;
}

void delnote()
{
    int c, state;

    state = 0;
    while ((c = getchar()) != EOF) {
        if (state == 0 && c == '/')         // ex. [/]
            state = 1;
        else if (state == 1 && c == '*')     // ex. [/*]
            state = 2;
        else if (state == 1 && c == '/')    // ex. [//]
            state = 4;
        else if (state == 1) {                // ex. [<secure/_stdio.h> or 5/3]
            putchar('/');
            state = 0;
        }

        else if (state == 2 && c == '*')    // ex. [/*he*]
            state = 3;
        else if (state == 2)                // ex. [/*heh]
            state = 2;

        else if (state == 3 && c == '/')    // ex. [/*heh*/]
            state = 0;
        else if (state == 3)                // ex. [/*heh*e]
            state = 2;

        else if (state == 4 && c == '\\')    // ex. [//hehe\]
            state = 9;
        else if (state == 9 && c == '\\')    // ex. [//hehe\\\\\]
            state = 9;
        else if (state == 9)                // ex. [//hehe\<enter> or //hehe\a]
            state = 4;
        else if (state == 4 && c == '\n')    // ex. [//hehe<enter>]
            state = 0;

        else if (state == 0 && c == '\'')     // ex. [']
            state = 5;
        else if (state == 5 && c == '\\')     // ex. ['\]
            state = 6;
        else if (state == 6)                // ex. ['\n or '\' or '\t etc.]
            state = 5;
        else if (state == 5 && c == '\'')    // ex. ['\n' or '\'' or '\t' ect.]
            state = 0;

        else if (state == 0 && c == '\"')    // ex. ["]
            state = 7;
        else if (state == 7 && c == '\\')     // ex. ["\]
            state = 8;
        else if (state == 8)                // ex. ["\n or "\" or "\t ect.]
            state = 7;
        else if (state == 7 && c == '\"')    // ex. ["\n" or "\"" or "\t" ect.]
            state = 0;

        if ((state == 0 && c != '/') || state == 5 || state == 6 || state == 7 || state == 8)
            putchar(c);
    }
}

Q:编写一个程序,查找C语言程序中的基本语法错误,如圆括号、方括号、花括号不配对。要正确处理引号(包括单引号和双引号)、转移字符序列与注释。(如果读者想把程序编写成完全通用的程序,难度会比较大。)
A://TODO 思路同上一题?也是类似如此,可以先把注释通过上面的程序去掉,剩下纯代码。整理出一个状态机,匹配语法的括号啊什么的(其实上面的思路里面对于引号就是个例子),又想了想,似乎还是有很多问题要处理,比如某一段就是缺少了对应的括号,怎么确定是错在这里的?打算搁置这个问题。。

标签:none

最后编辑于:2018/11/17 03:43

添加新评论