第四章——函数与程序结构

来源:互联网 发布:域名过户需要多长时间 编辑:程序博客网 时间:2024/06/03 05:48

      

一、函数的基本知识

       #include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int max);
int strindex(char source[], char searchfor[]);

char pattern[] = "ould";

int main(){//输入一行字符,getline()函数读取,便开始执行匹配查找工作
 char line[MAXLINE];
 int found = 0;
 char c;
 while (getline(line, MAXLINE) > 0&&(c=getchar())!=EOF)
  ;//在此添加输入中止和循环空语句,事实上输出只有最近包含关键字符串的一行
 //while (getline(line,MAXLINE))  //原本的while语句
 if (strindex(line, pattern) >= 0){
  printf("%s", line);
  found++;
 }
 return found;
}

int getline(char s[], int lim)
{//将行保存在s中,并返回该行的长度
 int c, i;
 i = 0;
 while (--lim && (c = getchar()) != EOF && c != '\n')
  s[i++] = c;
 if (c == '\n')
  s[i++] = c;
 s[i] = '\0';
 return i;//这里i为输入行长度

}

int  strindex(char s[], char t[])
{//返回t在s中的位置,若未找到返回-1
 int i, j, k;
 for (i = 0; s[i] != '\0'; i++){
  for (j = i, k = 0; t[k] != '\0'&& s[j] == t[k]; j++, k++)
   //这里我错写成了s[j]=t[k],而=优先级最低, t[k] == '\0'&& s[j]不是可修改的左值
   ;
  if (k > 0 && t[k] == '\0')
   return i;//这里的i为遍历到满足条件的行
 }
 return -1;
}


二、返回非整型值的函数

       #include <stdio.h>
#include <ctype.h>

#define MAXLINE 100

double atof(char s[]);
int getline(char c[], int n);

int main(){
 double sum, atof(char[]);
 char line[MAXLINE];
 int getline(char line[], int max);
 
 sum = 0;
 while (getline(line, MAXLINE) > 0)
  printf("\t%g\n", sum += atof(line));//输出科学计数的结果
 return 0;

}

double atof(char s[])
{//将字符串换为双精度浮点数
 double val, power;
 int i, sign;

 for (i = 0; isspace(s[i]); i++)//跳过空白符
  ;
 sign = (s[i] == '-') ? -1 : 1;
 if (s[i] == '+' || s[i] == '-')
  i++;
 for (val = 0.0; isdigit(s[i]); i++)//只有输入的数字才能继续进行
  val = 10.0*val + (s[i] - '0');
 if (s[i] = '.')
  i++;
 for (power = 1.0; isdigit(s[i]); i++)
 {
  val = 10.0*val + (s[i] - '0');
  power *= 10.0;
 }
 return sign*val / power;

}

int getline(char s[], int lim)
{//将一行读入到s,并返回长度
 int c, i;

 for (i = 0; i < lim - 1 && (c = getchar()) != EOF&&c != '\n'; i++)
  s[i] = c;
 if (c == '\n')
  s[i++] = c; //注意这里的自增
 s[i] = '\0';

 return i;
}

三、外部变量

#include <stdio.h>
#include <stdlib.h>  //为了使用atof()函数
#include <ctype.h> //为了使用isdigit()函数

#define MAXOP 100    //操作数或运算符的最大长度
#define NUMBER '0'   //标识找到一个数

int getop(char[]);
void push(double);
double pop(void);


 
//逆波兰计算器
int main(){
 int type;
 double op2;
 char s[MAXOP];

 while ((type = getop(s)) != EOF)
 {
  switch (type){
  case NUMBER:
   push(atof(s));//
   break;
  case '+':
   push(pop() + pop());
   break;
  case '-':
   op2 = pop();
   push(pop() - op2);
   break;
  case '*':
   push(pop()*pop());
   break;
  case '/':
   op2 = pop();
   if (op2 != 0.0)
    push(pop() / op2);
   else
    printf("error :zero divisor\n");
   break;
  case '\n':
   printf("\t%.8g\n", pop());
   break;//害死我了
  default:
   printf("error:unknown command %s\n", s);
   break;
  }
 }
 return 0;
}

#define MAXVAL 100//栈val的最大深度

int sp = 0;//下一个空闲栈位置
double val[MAXVAL];//值栈

void push(double f){//把f压入到值栈中
 if (sp < MAXVAL)
  val[sp++] = f;
 else
  printf("error: stack full ,can`t push %g\n", f);
}

double pop(void){//弹出并返回栈顶元素
 if (sp>0)
  return val[--sp];//栈指针原指向空
 else
  printf("error: stack empty\n");
 return 0.0;
}

int getch(void);
void ungetch(int);

int getop(char s[]){//获取下一个运算符或数值操作数
 int c = 0;
 int i = 0;

 while ((s[0] = c = getch()) == ' ' || c == '\t')
  ;
 s[1] = '\0';
 if (!isdigit(c) && c != '.')
  return c;//不是数
 //i = 0;
 if (isdigit(c))
 while (isdigit(s[++i] = c = getch()))//收集整数部分
  ;
 if (c == '.')
 while (isdigit(s[++i] = c = getch()))//收集小数部分
  ;
 s[i] = '\0';
 if (c != EOF)
  ungetch(c);
 return NUMBER;

}

#define BUFSIZE 100

char buf[BUFSIZE];//用于ungetch函数的缓冲区
int bufp = 0;//buf中下一个空闲位置

int getch(void){//取一个字符(可能是压回的字符)
 return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c){//把字符压回到输入中
 if (bufp >= BUFSIZE)
  printf("ungetch: too many characters\n");
 else
  buf[bufp++] = c;
}

四、作用域规则

       名字的作用域指的是程序中可以使用该名字的部分。

       变量声明用于说明变量的属性(主要是变量类型),而变量定义除此之外还将引起存储器的分配。

       一个外部变量只能在某个文件中定义一次,而其他文件可以通过extern声明来访问它。外部变量的定义中必须指定数组长度,但extern声明则不一定要指定数组的长度。

五、头文件

       就逆波兰计数器的程序中,代码分割如下:

          main.c:

              #include <stdio.h>

              #include <stdlib.h>

              #include "calc.h"

              #define MAXOP   100

              main(){

                ……

              }

         calc.h :

             #define NUMBER    '0'

             void push(double);

             double pop(void);

             int getop(char s[]);

             int getch(void);

             void ungetch(int);

         getop.c:

             #include <ctype.h>

             #include <stdio.h>

             #include "calc.h"

             int getop(char s[]){

              ……

             }

         stack.c:

             #include <stdio.h>

            // #include "calc.h"

             #define  MAXVAL    100

             int sp;

             double val[MAXVAL];

             void push(double){

             ……

              }

             double pop(void){

             ……

              }

          getch.c:

             #include <stdio.h>

            // #include "calc.h"  

             #define BUFSIZE 100

             char buf[BUFSIZE];

             int bufp=0;

             int getch(void){

              ……

              }

             void ungetch(int) {

              ……

              }




六、静态变量

       通过static限定外部对象,可以达到隐藏外部对象的目的。也可以用于声明函数,则该函数名除了对该函数声明所在的文件可见外,其他文件都无法访问。

       static类型的内部变量是一种只能在某个特定函数中使用但一直占据存储空间的变量。

七、寄存器变量

       将register变量放在机器的寄存器中,这样使程序更小,执行速度更快。

       register声明只适用于自动变量以及函数的形式参数。

       无论寄存器变量实际上是不是存放在寄存器中,它的地址都是不可访问的。

八、程序块结构

       不允许在函数中定义函数。

       静态变量只在第一次进入程序块时被初始化一次。

九、初始化

       对于外部变量和静态变量来说,初始化表达式必须是常量表达式,且只初始化一次。

十、递归

       函数递归调用自身时,每次调用都会得到一个与以前的自动变量集合不同的新的自动变量。

       递归效率低(递归调用中必须在某个地方维护一个存储处理值的栈),但递归代码比较紧凑

十一、C预处理器

       1、文件包含

            #include <>

            #include " "

       2、宏替换

            #define   名字   替换文本

       3、条件包含

            #if

            #endif

            #elif

            #ifdef

            #ifndef




0 0
原创粉丝点击