⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c primer plus

📁 系统地学习、撑握C语言的经典书。 这是我整理、加工过的《C Primer Plus》精简版
💻
📖 第 1 页 / 共 5 页
字号:

// 输入的首个非空字符
char get_first(void);

// 输入一个整型
int get_int(void);

// 
void count(void);

int main(void)
{
	int choice;
	void count(void);

	while ( (choice = get_choice()) != 'q')
	{
		switch (choice)
		{
		case 'a' :  printf("Buy low, sell high.\n");
			break;
		case 'b' :  putchar('\a');  /* ANSI */
			break;
		case 'c' :  count();
			break;
		default  :  printf("Program error!\n");
			break;
		}
	}
	printf("Bye.\n");

	return 0;
}

void count(void)
{
	int n,i;

	printf("Count how far? Enter an integer:\n");
	n = get_int();
	for (i = 1; i <= n; i++)
		printf("%d\n", i);
	while ( getchar() != '\n')
		continue;
}

char get_choice(void)
{
	int ch;

	printf("Enter the letter of your choice:\n");
	printf("a. advice           b. bell\n");
	printf("c. count            q. quit\n");
	ch = get_first();
	while (  (ch < 'a' || ch > 'c') && ch != 'q')
	{
		printf("Please respond with a, b, c, or q.\n");
		ch = get_first();
	}

	return ch;
}

char get_first(void)
{
	int ch;

	ch = getchar();
	while (getchar() != '\n')
		continue;

	return ch;
}

int get_int(void)
{
	int input;
	char ch;

	while (scanf("%d", &input) != 1)
	{
		while ((ch = getchar()) != '\n')
			putchar(ch);  // 删除错误的输入
		printf(" is not an integer.\nPlease enter an ");
		printf("integer value, such as 25, -178, or 3: ");
	}

	return input;
}




第九章 函数

1、为什么使用函数?

第一、代码重用,写一次,调用多次,避免重复写代码;
第二、函数使得程序更模块化,可读性高。有些函数可能只调用一次也是有必要。


2、ANSI C 要求每个参数前声明其类型。

void dibs(int x, y, x)		// 错误
{
	//...
}

void dibs(int x, int y, int x)	// 正确,前面的void意思是无返回值
{
	//...
}

void dibs(x, y, z)		// 这种方式已废弃
int x, y, z;
{
	//...
}


void show_n()			// 正确,但ANSI C标准将会删除此方式
{
	//...
}

void show_n(void)		// 推荐,可能旧的编译器不支持,后面的void表示无参数
{
	//...
}


int pritnf(char *, ...);	// ... 表示参数不确定,可能是一个或几个。参见 stdarg.h 


3、函数声明、定义

方式1:先声明函数,后定义函数。推荐!

//int max(int, int);		// 声明方式1
int max(int a, int b);		// 声明方式2

void main(void)
{
	int a = max(3, 5);
	printf("%n", a);
}

//max(int a, int b)		// 早期C允许不定义返回类型,默认为int,但C99不再支持默认类型
int max(int a, int b)		// 定义函数
{
	return (a > b) ? a : b;
}


方式2:在调用前定义函数。对于较小的函数可接受此方试。

int max(int a, int b)		// 定义max()函数
{
	return (a > b) ? a : b;
}

void main(void)
{
	int a = max(3, 5);	// 调用max()函数
	printf("%n", a);
}


3、许多程序更倾向只在函数结尾使用一次return语句,因为这样做有利于理解执行流程。


4、递归分析

C函数地位同等,也就是一个函数可以调用其他任何函数,也可以调用自己。
就算是main()也可以被其他函数调用,只不过一般不会这么做。


/* recur.c -- recursion illustration */
#include <stdio.h>
void up_and_down(int);

int main(void)
{
    up_and_down(1);
    return 0;
}

void up_and_down(int n)
{
    printf("Level %d: n location %p\n", n, &n); /* 1 */ 
    if (n < 4)
         up_and_down(n+1);
    printf("LEVEL %d: n location %p\n", n, &n); /* 2 */  
 
}

输出结果:
Level 1: n location 0012FE98
Level 2: n location 0012FDC0
Level 3: n location 0012FCE8
Level 4: n location 0012FC10
LEVEL 4: n location 0012FC10
LEVEL 3: n location 0012FCE8
LEVEL 2: n location 0012FDC0
LEVEL 1: n location 0012FE98

递归方式很消耗内存:每次递归调用需要把新的变量集合存储在堆栈中。
不过有些功能是无法用循环实现的,而采用递归方式很容易就能实现。


long Fibonacci(int n);	// 计算斐波纳契数列值
{
	if(n > 2)
		return Fibonacci(n-1) + Pibonacci(n-2);
	else
		return 1;
}

采用双重递归,每级调用需要的变量数是上一级变量数的2位,也就是以指数规则增长,
指数增长的变量会占用大量内存,可能会导致程序瘫痪。


5、递归与循环

long fact(int n)     // 使用循环计算阶乘
{
	long ans;

	for (ans = 1; n > 1; n--)
		ans *= n;

	return ans;
}

long rfact(int n)    // 使用递归计算阶乘
{
	long ans;

	if (n > 0)
		ans= n * rfact(n-1);
	else
		ans = 1;

	return ans;
}

上面这两种实现方式,循环方式比递归更快些,因为递归方式需要更多内存,读写内存次数更多。


6、使用头文件

/* usehotel.c -- room rate program */
/* compile with  Listing 9.10      */
#include <stdio.h>
#include "hotel.h" /* defines constants, declares functions */

int main(void)
{
   int nights;
   double hotel_rate;
   int code;

   while ((code = menu()) != QUIT)
   {
      switch(code)
      {
      case 1 : hotel_rate = HOTEL1;
               break;
      case 2 : hotel_rate = HOTEL2;
               break;
      case 3 : hotel_rate = HOTEL3;
               break;
      case 4 : hotel_rate = HOTEL4;
               break;
      default: hotel_rate = 0.0;
               printf("Oops!\n");
               break;
      }
      nights = getnights();
      showprice(hotel_rate, nights);
   }
   printf("Thank you and goodbye.");
   
   return 0;
}


/* hotel.h -- constants and declarations for hotel.c */
#define QUIT       5
#define HOTEL1    80.00
#define HOTEL2   125.00
#define HOTEL3   155.00
#define HOTEL4   200.00
#define DISCOUNT   0.95
#define STARS "**********************************"

// shows list of choices
int menu(void);

// returns number of nights desired
int getnights(void);

// calculates price from rate, nights
// and displays result
void showprice(double rate, int nights);


/* hotel.c -- hotel management functions */
#include <stdio.h>
#include "hotel.h"
int menu(void)
{
    int code, status;

    printf("\n%s%s\n", STARS, STARS);
    printf("Enter the number of the desired hotel:\n");
    printf("1) Fairfield Arms           2) Hotel Olympic\n");
    printf("3) Chertworthy Plaza        4) The Stockton\n");
    printf("5) quit\n");
    printf("%s%s\n", STARS, STARS);
    while ((status = scanf("%d", &code)) != 1  ||
             (code < 1 || code > 5))
   {
        if (status != 1)
            scanf("%*s");
        printf("Enter an integer from 1 to 5, please.\n");
    }
   
    return code;
}

int getnights(void)
{
    int nights;

    printf("How many nights are needed? ");
    while (scanf("%d", &nights) != 1)
    {
        scanf("%*s");
        printf("Please enter an integer, such as 2.\n");
    }
   
    return nights;
}

void showprice(double rate, int nights)
{
    int n;
    double total = 0.0;
    double factor = 1.0;

    for (n = 1; n <= nights; n++, factor *= DISCOUNT)
        total += rate * factor;
    printf("The total cost will be $%0.2f.\n", total);
}


7、指针(pointer)

/* swap3.c -- using pointers to make swapping work */
#include <stdio.h>
void interchange(int * u, int * v);

int main(void)
{
    int x = 5, y = 10;

    printf("Originally x = %d and y = %d.\n", x, y);
    interchange(&x, &y);  // &x 表示变量x的所在内存单元的地址
    printf("Now x = %d and y = %d.\n", x, y);

    return 0;
}

// 互相交换两个整数
void interchange(int * px, int * py)	// int * px 表示声明一个指针变量
{
    int temp;

    temp = *px;		// *px 表示px指向的内存单元的值
    *px = *py;
    *py = temp;
}



第十章 数组和指针

1、数组声明、初始化

	int powers[4] = {11, 20, 5, 3};	// 声明4个整数的数组,并初始化
					// 这种初始化方式只有 ANSI C 支持这种初始化方式
					// 如果您的编译器不支持,尝试一下在int前面加 static

	for (i=0; i<4; i++)		// 4 可以写成 sizeof(powers)/sizeof(powers[0]),编译器会计算为4
		printf("%d ", powers[i]);

	int arr1[5] = {0, 0, 0, 0, 22};	// 传统的初始化方式
	int arr2[5] = {[4]=22};		// C99新增初始化方式,有些编译器还不支持

	char str1[3] = {'a', 'b'};	// 声明3个字符的数组,并初始化
	const char str2[12] = "string2";// 声明12个字符的常量数组,并初始化
	printf("%s\n", str1);
	printf("%s\n", str2);


在声明变量或数组时不初始化,是不会编译成指令的;在声明时初始化,实际上会被编译器编译成一些指令。


2、为数组赋值

	#define SIZE 5

	int oxen[SIZE] = {5, 3, 2, 8};	// 正确
	int yaks[SIZE];

	yaks = oxen;			// 不允许
	yaks[SIZE] = oxen[SIZE];	// 不正确
	yaks[SIZE] = {5, 3, 2, 8};	// 不起作用

	int i;
	for (i=0; i<SIZE ; i++)
		oxen[i] = i;		// 正确


3、C程序不会自动检查数组边界,以确保运行速率更快,程序员必须避免越界问题。


4、指定数组大小

	const int n = 5;
	int m = 8;

	float a1[5];			// 可以
	float a2[5*2+1];		// 可以
	float a3[sizeof(int)+1];	// 可以

	float a4[-4];			// 不可以,数组大小必须大于0
	float a5[0];			// 不可以,数组大小必须大于0
	float a6[2.5];			// 不可以,数组大小必须是整数

	float a7[(int)2.5];		// 可以,强制将float转成int
	float a8[n];			// 可以,n为整数常量
	float a9[m];			// 变长数组(VLA -- variable-length array),C99之前不允许



5、多维数组

	// 二维数组:aar2为3行5列的二维数组,共有15个元素;初始化的内花括号可以省去
	float arr2[3][5] = {
		{1.1, 1.2, 1.3, 1.4, 1.5},
		{2.1, 2.2, 2.3, 2.4, 2.5},
		{3.1, 3.2, 3.3, 3.4, 3.5}  };

	// 三维数组,C还支持更多维数组
	float arr3[3][4][6];


6、数组与指针

// pnt_add.c -- pointer addition
#include <stdio.h>
#define SIZE 4
int main(void)
{
	short dates [SIZE];
	short * pti;
	
	double bills[SIZE];
	double * ptf;

	short index;

	pti = dates;    // assign address of array to pointer
	ptf = bills;
	printf("%23s %10s\n", "short", "double");
	for (index = 0; index < SIZE; index ++)
	{
		printf("pointers + %d: %10p %10p\n",
			index, 
			pti + index,	// pti 是short指针,每加1,它的值就加sizeof(short),即加2字节
			ptf + index	// ptf 是double指针,每加1,它的值就加sizeof(double), 即加8字节
			);
	}

	return 0;
}
输出结果类似:
                  short     double
pointers + 0:   0012FF58   0012FF24
pointers + 1:   0012FF5A   0012FF2C
pointers + 2:   0012FF5C   0012FF34
pointers + 3:   0012FF5E   0012FF3C

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -