星海's Blog

老头初学编程

第一章:计算机系统基础知识

1,计算机系统的硬件组成

 

CPU:Central Processing Unit, CPU

运算器是对数据进行加工处理的部件,它主要完成算术和逻辑运算。

控制器的主要功能则是从主存中取出指令并进行分析,控制计算机的各个部件有条不紊的完成指令的功能。

存储器是记忆设备——1,内部存储器(Main Memory, MM, 简称内存) 2,外存

寄存器是CPU中的记忆设备,用来存放指令,数据及运算结果。

 

2,计算机的类型和应用领域

按照功能是否单一,计算机可分为通用计算机和专用(嵌入式)计算机。

按照CPU指令系统架构,计算机分为复杂指令系统计算机(Complex Instruction Set Computer, CISC) 和 精简指令系统计算机(Reduced Instruction Set Computer, RISC).

按体系结构及指令处理方式,计算机分为四种(X指令流X数据流,simple,multiple)

 

3,机器数和码制

带符号的机器数可采用:

1,原码:最高位是符号位,其余的(n-1)位表示数值的绝对值

0有两种表示方式:000000...或10000..(-0)

2,反码:负数的反码是其绝对值按位求反。

0有两种表现方式:00000000或1111111

3,补码:负数的补码等于其反码的末尾+1。

4,移码:移码表示法是在数X上增加一个偏移量来定义的,常用于表示浮点数中的阶码。如果机器字长为n,在偏移2n-1的情况下,只要将补码的符号位取反便可获得相应的移码表示。

0= 100000....

1 = 10000...1

 

4,定点数和浮点数

定点数就是表示数据时小数点的位置固定不变。纯整数,纯小数。

原码/反码 定点整数范围: -(2n-1-1) ~ +(2n-1-1)

原码/反码 定点小数范围: -(1-2-(n-1)) ~ +(1-2-(n-1))

补码/移码 定点整数范围:-2n-1 ~ +(2n-1-1)

补码/移码 定点小数范围:-1 ~ +(1- 2-(n-1))

 

浮点数是小数点位置不变的数,能表示更大范围的数

一个含小数点的二进制数N可表示为更一般的形式:

N = 2E * F

其中,E称为阶码,浮点表示法中,通常为带符号的纯整数,

F为尾数,通常为带符号的纯小数。

 

IEEE754(IEEE制定的浮点数工业标准)中,表示为SPM

其中,S为数的符号位0|1。P为阶码,通常用移码表示,M为尾数,用原码表示,且规格化,去掉首位的1。

值                 存储为               指数                                                    偏移量
单精度:     1位符号位(s)、8位指数(e),23位尾数(m,共32位)      127(7FH)
双精度:     1位符号位(s)、11位指数(e),52位尾数(m,共64位)    1023(3FFH)
扩充精度: 1位符号位(s)、15位指数(e),64位尾数(m,共80位)    16383(3FFFH)

阶码用移码表示,移码的偏移值并不是通常n位移码所用的2n-1,而是2n-1-1,这是因为尾数规格化后必须为0.100..0,而我们现在尾数用1.000..00表示,即尾数左移1位,所以阶码偏移值为2n-1-1。

也可以用(指数补码-1),然后符号位取反获得。

5,BCD码

四位二进制来表示一位十进制,二-十进制编码,简称BCD编码。

8421码——普通   

余3码——在8421码基础上,把每个数的代码加上0011后构成

格雷码——相邻的两个代码之间只有一位不同。

如果使用BCD码进行计算,可能需要进行修正。

如8421码中,6+7= 0110 + 0111 = 1101,不在BCD码表示范围里。修正的方法是 本位+6,向高位进1。

1101+ 0110 = 0011 为3,高位为1,结果为13.

 

余3码进行计算中,从最高位产生的进位是真正的进位,对每4位的结果,如果是小于等于9的,则减3,如果大于9,则加3.

6,汉字编码

汉字内码:

GB2312-80 两个字节存放一个汉字的内码,每个字节最高位置为1。可表示2^14个 16384 汉字。

ISO/IEC 10646标准,通用多8位编码字符集 UCS(Universal Code Set):4个八位码。 组(最高位不用),平面、行、字位。

 

7,校验码

码距是校验码中的一个重要概念,指一个编码系统中任意两个合法编码之间至少有多少个二进制位不同。

(1) 奇偶校验码:在编码中增加一个校验位来使编码中1的个数为奇数或者偶数,从而使码距变为2。只可以检测代码中有奇数位出错的代码。

水平奇偶、垂直奇偶、水平垂直奇偶校验。

(2) 海明码:

一般来说,若信息位为k位,冗余位为r位,则数据位n=k+r,用r的监督关系式来产生r个校正因子,区分无错和在n个不同的位置的一位错,则要求满足公式 2r >= n+1  或  2r >= k+r+1     

此式子称为海明公式,r叫海明距离,若k=4时则r>=3,当取r=3时,n=k+r=4+3=7

校验码位置为 2n

8位数为例(不完全,只适合初级理解)

P1 = 0 1 3 4 6

P2 = 0 2 3 5 6

P3 = 1 2 3 7

P4 = 4 5 6 7

(3) 循环冗余校验码:

求CRC编码时,采用的是模2运算。

8,逻辑代数与逻辑运算

常用逻辑公式:

其他公式: $AB+A\overline{B}=A$ $A+AB=A$

$AB+\overline{A}C+BC=AB+\overline{A}C$

$\overline{A\oplus{B}}=\overline{A}\oplus{B}=A\oplus{\overline{B}}$

 

例题:化简逻辑表达式 $\overline{ABC}+\overline{AB}C+\overline{A}BC+A\overline{BC}+A\overline{B}C+ABC$

 

9,补码加减法溢出判断机制

1,双符号判决法:

用额外两位表示符号,00表示正号,11表示符号。则溢出时结果的两个符号位就不一样了,从而可以判定发生溢出。 VF= S2 ^ S1

例1: x = +110110, y = -110011

则x - y = x + (-y)补码,即为 00110110 + 11001101

\begin{tabular} {cD} & 00 0110110\\ +&11 1001101\\ \hline = &00 0000011 0^0 = 0,没有溢出

例2: x = -1111000, y = -10010

\begin{tabular} {cD} & 11 0001000\\ +&11 1101110\\ \hline = &10 1110110 1^0 =1,溢出

 

2,进位判决法:

Cn-1表示最高数值位想最高位的进位,Cn表示符号位的进位, 则 VF = Cn-1 ^ Cn 表示溢出

 

3,同号数求和或异号数求差时,可根据符号位与进位判定溢出。 VF = SF ^ CF

 

4, 若用X,Y,Z表示两个操作数及运算结果的符号位。 VF = (X & Y & ~Z) | (~X & ~Y & Z)

 

10,浮点运算

1,浮点加减

1)对阶,使两个数阶码相同

2) 求尾数和(差)

3) 结果规格化

4) 舍入。尾数最低位因为过长被丢掉。处理方法有 截断法 末位恒1法,0舍1入法。

5) 溢出判别。若阶码溢出,则结果溢出。若阶码下溢(小于最小值),则结果为0。

 

2,浮点乘除

积的阶码等于两乘数的阶码相加,尾数等于两乘数尾数相乘。

商的阶码等于被除数的阶码减去出书的阶码,尾数等于被除数的尾数除以除数的尾数。

然后规格化并判定溢出。

 

节选自2003年软考试题

若在系统中有若干个互斥资源R,6个并发进程,每个进程都需要5个资源R,那么使系统不发生死锁的资源R的最少数目为_____ 。
A.30 B.25 C.10 D.5

还有一道,2005年11月的试题,同样类型

系统中有4个单位的存储器资源,被n个进程共享,如果每个进程都要求i个单位的存储器资源,那么当————市,系统不会发生死锁。

A n=2, i=4
B,n=4, i=3
C,n=3, i=2
D,n=3, i=3

C素数筛法(更新中)

#include 	<stdio.h>
#include	<stdlib.h>
#include	<math.h>
#include	<stdbool.h>
#include	<time.h>

unsigned int prime(unsigned int max)
{
	unsigned int count = 0;	/* 返回count: 素数个数 */
	unsigned int i, j, k;

// 申请内存
	bool *sieve = (bool *) malloc(sizeof(bool) * (max));
	if (sieve == NULL) {
		fprintf(stderr, "\ndynamic memory allocation failed\n");
		exit(EXIT_FAILURE);
	}

	sieve[0] = false;
	sieve[1] = false;
	sieve[2] = true;

//除2之外,所有偶数都是合数
	for (i = 3; i < max; i++)
		if (i % 2)
			sieve[i] = true;
		else
			sieve[i] = false;

	k = (int)sqrt(max);

	for (i = 2; i < k; i++) {
		if (sieve[i])
			for (j = i + i; j < max; j += i) {
				sieve[j] = false;
			}
	}

	for (i = 0; i < max; i++)
		if (sieve[i])
			count++;

	free(sieve);
	sieve = NULL;

	return count;
}

int main(void)
{
	unsigned int count;
	unsigned int N = 100000000;
	clock_t start, end;

	start = clock();
	count = prime(N);

	end = clock();
	printf("[%u]以内素数个数%u 计算用时:%g 秒\n", N, count,
	       (double)(end - start) / (double)CLOCKS_PER_SEC);
}

[100000000]以内素数个数5761455 计算用时:5.86 秒

#include    <stdio.h>
#include    <stdlib.h>
#include    <math.h>
#include    <stdbool.h>
#include    <time.h>

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  prime
 *  Description:  只存奇数的bool型数组,素数筛法。[0]表示自然数3
 * =====================================================================================
 */
unsigned int prime(unsigned int max)
{
    unsigned int count = 1;    /* 返回count: 素数个数,已经包括2,所以count为1 */
    unsigned int limit = max / 2 - 1;    /* max以内的素数用到的数组需要空间 max/2-1 */
    unsigned int i, k;
    unsigned int multiprime;

// 申请内存,       
    bool *sieve = (bool *) malloc(sizeof(bool) * (limit));
    if (sieve == NULL) {
        fprintf(stderr, "\ndynamic memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < limit; i++)
        sieve[i] = true;

// 2*i+3 为数组下标内容所代表的数值

    k = (unsigned int)sqrt(max);
    for (i = 0; 2 * i + 3 < k; i++) {
        if (sieve[i]) {
            int temp = 2 * i + 3;    /* temp代表数组下标所代表的真实数值 */
            /* 索引i所代表数值的奇数倍索引,3倍时为3*temp */
            for (multiprime = temp * 3; multiprime < max;
                 multiprime += 2 * temp)
                sieve[(multiprime - 3) / 2] = false;
        }

    }

    for (i = 0; i < limit; i++)
        if (sieve[i])
            count++;

    free(sieve);
    sieve = NULL;

    return count;
}

int main(void)
{
    unsigned int count;
    unsigned int N = 100000000;
    clock_t start, end;

    start = clock();
    count = prime(N);

    end = clock();
    printf("[%u]以内素数个数%u 计算用时:%g 秒\n", N, count,
           (double)(end - start) / (double)CLOCKS_PER_SEC);
}

[100000000]以内素数个数5761455 计算用时:2.85 秒

#include 	<stdio.h>
#include	<stdlib.h>
#include	<math.h>
#include	<stdbool.h>
#include	<time.h>

unsigned int prime(unsigned int max)
{
	unsigned int count = 0;	/* 返回count: 素数个数 */
	unsigned int i, j, k;

// 申请内存
	bool *sieve = (bool *) malloc(sizeof(bool) * (max));
	if (sieve == NULL) {
		fprintf(stderr, "\ndynamic memory allocation failed\n");
		exit(EXIT_FAILURE);
	}

	sieve[0] = false;
	sieve[1] = false;
	sieve[2] = true;

//除2之外,所有偶数都是合数
	for (i = 3; i < max; i++)
		if (i % 2)
			sieve[i] = true;
		else
			sieve[i] = false;

	k = (int)sqrt(max);

	/*------------------------------------------------------------------
	 *  台湾ACMTino同学的算法:i是素数,则下一个起点是i*i,把后面所有的i*i+2*x*i筛掉
         *  我的实现还不完备
	 *----------------------------------------------------------------*/
	for (i = 2; i < k; i++) {
		if (sieve[i])
			for (j = i * i; j < max; j += 2 * i) {
				sieve[j] = false;
			}
	}

	for (i = 0; i < max; i++)
		if (sieve[i])
			count++;

	free(sieve);
	sieve = NULL;

	return count;
}

int main(void)
{
	unsigned int count;
	unsigned int N = 100000000;
	clock_t start, end;

	start = clock();
	count = prime(N);

	end = clock();
	printf("[%u]以内素数个数%u 计算用时:%g 秒\n", N, count,
	       (double)(end - start) / (double)CLOCKS_PER_SEC);
}

[100000000]以内素数个数5761455 计算用时:3.53 秒

#include     <stdio.h>
#include    <stdlib.h>
#include    <math.h>
#include    <string.h>
#include    <time.h>
#include    <stdbool.h>

/*
 * ===  FUNCTION  ======================================================================
 *  Description:  只计算奇数数组里的奇数是否为素数,[0]为3
 *          prime(n)中的n为n以内的素数,不包括n本身。
 * =====================================================================================
 */
int prime(unsigned int n)
{
    unsigned int i, j, k;
    unsigned int limit = n / 2 - 1;

    unsigned int count = 1;    /* 数组中不包含的2也为素数 */
    bool *sieve = (bool *) malloc(sizeof(bool) * limit);
    if (sieve == NULL) {
        fprintf(stderr, "\ndynamic memory allocation failed\n");
        exit(EXIT_FAILURE);
    }
    for (i = 0; i < limit; i++)
        sieve[i] = true;

    j = (unsigned int)sqrt(n);
    for (i = 0; 2 * i + 3 <= j; i++)
        if (sieve[i]) {
            int temp = 2 * i + 3;    /* 2*i+3为数组下标实际代表的数值 */
            for (k = temp * temp; k <= n; k += 2 * temp)    /* x是素数,则下一个起点是x*x,并把后面所有的x*x+2*x*i筛掉 */
                sieve[(k - 3) / 2] = false;
        }
    for (i = 0; i < limit; i++)
        if (sieve[i])
            count++;

    free(sieve);
    sieve = NULL;

    return count;

}

int main(int argc, char *argv[])
{
    unsigned int count;
    unsigned int N = 100000001;
    clock_t start, end;

    start = clock();
    count = prime(N);

    end = clock();
    printf("[%u]以内素数个数%u 计算用时:%g 秒\n", N, count,
           (double)(end - start) / (double)CLOCKS_PER_SEC);
    return 0;
}

[100000000]以内素数个数5761455 计算用时:2.56 秒

/*-----------------------------------------------------------------------------
 *  可参考论文COMPUTING π(x): THE MEISSEL-LEHMER METHOD
 *  以下函数为百度C语言贴吧 5230所做 (我完全不懂撒 -__-)
 *-----------------------------------------------------------------------------*/
#include	<stdio.h>
#include	<string.h>
#include	<stdlib.h>
#include	<time.h>
#include	<math.h>

int *primarr, *v;
int q = 1, p = 1;

//π(n)
int pi(int n, int primarr[], int len)
{
	int i = 0, mark = 0;
	for (i = len - 1; i > 0; i--) {
		if (primarr[i] < n) {
			mark = 1;
			break;
		}
	}
	if (mark)
		return i + 1;
	return 0;
}

//Φ(x,a)
int phi(int x, int a, int m)
{
	if (a == m)
		return (x / q) * p + v[x % q];
	if (x < primarr[a - 1])
		return 1;
	return phi(x, a - 1, m) - phi(x / primarr[a - 1], a - 1, m);
}

int prime(int n)
{
	char *mark;
	int mark_len;
	int count = 0;
	int i, j, m = 7;
	int sum = 0, s = 0;
	int len, len2, len3;

	mark_len = (n < 10000) ? 10002 : ((int)exp(2.0 / 3 * log(n)) + 1);

	//筛选n^(2/3)或n内的素数
	mark = (char *)malloc(sizeof(char) * mark_len);
	memset(mark, 0, sizeof(char) * mark_len);
	for (i = 2; i < (int)sqrt(mark_len); i++) {
		if (mark[i])
			continue;
		for (j = i + i; j < mark_len; j += i)
			mark[j] = 1;
	}
	mark[0] = mark[1] = 1;

	//统计素数数目
	for (i = 0; i < mark_len; i++)
		if (!mark[i])
			count++;

	//保存素数
	primarr = (int *)malloc(sizeof(int) * count);
	j = 0;
	for (i = 0; i < mark_len; i++)
		if (!mark[i])
			primarr[j++] = i;

	if (n < 10000)
		return pi(n, primarr, count);

	//n^(1/3)内的素数数目
	len = pi((int)exp(1.0 / 3 * log(n)), primarr, count);
	//n^(1/2)内的素数数目
	len2 = pi((int)sqrt(n), primarr, count);
	//n^(2/3)内的素数数目
	len3 = pi(mark_len - 1, primarr, count);

	//乘积个数
	j = mark_len - 2;
	for (i = (int)exp(1.0 / 3 * log(n)); i <= (int)sqrt(n); i++) {
		if (!mark[i]) {
			while (i * j > n) {
				if (!mark[j])
					s++;
				j--;
			}
			sum += s;
		}
	}
	free(mark);
	sum = (len2 - len) * len3 - sum;
	sum += (len * (len - 1) - len2 * (len2 - 1)) / 2;

	//欧拉函数
	if (m > len)
		m = len;
	for (i = 0; i < m; i++) {
		q *= primarr[i];
		p *= primarr[i] - 1;
	}
	v = (int *)malloc(sizeof(int) * q);
	for (i = 0; i < q; i++)
		v[i] = i;
	for (i = 0; i < m; i++)
		for (j = q - 1; j >= 0; j--)
			v[j] -= v[j / primarr[i]];

	sum = phi(n, len, m) - sum + len - 1;
	free(primarr);
	free(v);
	return sum;
}

int main()
{
	int n;
	int count;
	clock_t start, end;
	scanf("%d", &n);

	start = clock();
	count = prime(n);
	end = clock() - start;
	printf
	    ("[%d]内的素数个数为%d,计算用时:%d毫秒\n",
	     n, count, (int)end / 1000);
	getchar();
	return 0;
}

 

CPP第五版 课后题

 


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

#define MAXNUM 19		/* 球员数 */
#define MAXNAMECH 20		/* 名字最大字符树 */
#define MAXCHAR 80		/* 棒球队一行中最多字符数 */

struct nine {
	char first[MAXNAMECH];
	char last[MAXNAMECH];
	int gp;			/* 出场次数 */
	int ab;			/* 击中数 */
	int tob;		/* 走垒数 */
	int rbi;		/* 跑点数 */
	double sucrate;		/* 成功率 */
};

/*-----------------------------------------------------------------------------
 *  思路:用一个临时字符串存放棒球队信息文件中一行的字符数据
 *  调用sscanf将字符转换为struct结构中相应数据项
 *-----------------------------------------------------------------------------*/

int main(void)
{
	char line[MAXCHAR];
	int num;
	int tmpgp, tmpab, tmptob, tmprbi;	/* 临时存放结构数据 */

	struct nine temp[MAXNUM];
	memset(temp, 0, sizeof(struct nine) * MAXNUM);

	FILE *fp;		/* input-file pointer */
	char *fp_file_name = "nines.dat";	/* input-file name    */

	fp = fopen(fp_file_name, "r");
	if (fp == NULL) {
		fprintf(stderr, "couldn't open file '%s'; %s\n",
			fp_file_name, strerror(errno));
		exit(EXIT_FAILURE);
	}
	while (fgets(line, MAXCHAR - 1, fp) != NULL) {
		sscanf(line, "%d", &num);
		sscanf(line, "%*d %[^ ] %[^ ] %d %d %d %d", temp[num].first,
		       temp[num].last, &tmpgp, &tmpab, &tmptob, &tmprbi);
		temp[num].gp += tmpgp;
		temp[num].ab += tmpab;
		temp[num].tob += tmptob;
		temp[num].rbi += tmprbi;
	}

	puts("号码  1stname  lastname  上场次数  击中数  走垒数  跑点数  成功率\n");
	for (num = 0; num < MAXNUM; num++) {
		if (temp[num].gp != 0)
			temp[num].sucrate = (float)temp[num].ab / temp[num].gp;
		printf
		    ("%-4d  %-8s  %-8s  %-8d  %-6d  %-6d  %-6d  %.2f\n",
		     num, temp[num].first, temp[num].last, temp[num].gp,
		     temp[num].ab, temp[num].tob, temp[num].rbi,
		     temp[num].sucrate);

	}

	if (fclose(fp) == EOF) {	/* close input file   */
		fprintf(stderr, "couldn't close file '%s'; %s\n",
			fp_file_name, strerror(errno));
		exit(EXIT_FAILURE);
	}
	return 0;
}

 

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define ID_MASK     0xFF
#define SIZE_MASK   0x7F00
#define LEFT        0x00000
#define CENTER      0x08000
#define RIGHT       0x10000
#define ALIGN_MASK  0x18000
#define REGULAR     0x00000
#define BOLD        0x20000
#define ITALIC      0x40000
#define UNDERLINE   0x80000
#define STYLE_MASK  0xE0000
#define SIZE_SHIFT  8
typedef unsigned long font;

char do_menu(font * f);
char get_choice(const char *);
void show_menu(void);
void show_font(font f);
void eatline(void);
void get_id(font * f);
void get_size(font * f);
void get_align(font * f);

int main(void)
{
	font sample = 1 | (12 << SIZE_SHIFT) | LEFT | ITALIC;

	while (do_menu(&sample) != 'q')
		continue;
	puts("Bye!");
	return 0;
}

char do_menu(font * f)
{
	char response;

	show_font(*f);
	show_menu();
	response = get_choice("fsabiuq");
	switch (response) {
	case 'f':
		get_id(f);
		break;
	case 's':
		get_size(f);
		break;
	case 'a':
		get_align(f);
		break;
	case 'b':
		*f ^= BOLD;
		break;
	case 'i':
		*f ^= ITALIC;
		break;
	case 'u':
		*f ^= UNDERLINE;
		break;
	case 'q':
		break;
	default:
		fprintf(stderr, "menu problem\n");
	}

	return response;
}

char get_choice(const char *str)
{
	char ch;

	ch = getchar();
	ch = tolower(ch);
	eatline();
	while (strchr(str, ch) == NULL) {
		printf("Please enter one of the following: %s\n", str);
		ch = tolower(getchar());
		eatline();
	}
	return ch;
}

void eatline(void)
{
	while (getchar() != '\n')
		continue;
}

void show_menu(void)
{
	puts("f)change font    s)change size    a)change alignment");
	puts("b)toggle bold    i)toggle italic  u)toggle underline");
	puts("q)quit");
}

void show_font(font f)
{
	printf("\n%4s %4s %9s %3s %3s %3s\n",
	       "ID", "SIZE", "ALIGNMENT", "B", "I", "U");
	printf("%4ld %4ld", f & ID_MASK, (f & SIZE_MASK) >> SIZE_SHIFT);
	switch (f & ALIGN_MASK) {
	case LEFT:
		printf("%7s", "left");
		break;
	case RIGHT:
		printf("%7s", "right");
		break;
	case CENTER:
		printf("%7s", "center");
		break;
	default:
		printf("%7s", "unknown");
		break;
	}
	printf("%8s %3s %3s\n\n", (f & BOLD) == BOLD ? "on" : "off",
	       (f & ITALIC) == ITALIC ? "on" : "off",
	       (f & UNDERLINE) == UNDERLINE ? "on" : "off");
}

void get_id(font * f)
{
	int id;

	printf("Enter font ID (0-255): ");
	scanf("%d", &id);
	id = id & ID_MASK;
	*f |= id;
	eatline();
}

void get_size(font * f)
{
	int size;

	printf("Enter font size (0-127): ");
	scanf("%d", &size);
	*f |= (size << SIZE_SHIFT) & SIZE_MASK;
	eatline();
}

void get_align(font * f)
{
	puts("Select alignment:");
	puts("l)left   c)center   r)right");
	switch (get_choice("lcr")) {
	case 'l':
		*f &= ~ALIGN_MASK;
		*f |= LEFT;
		break;
	case 'c':
		*f &= ~ALIGN_MASK;
		*f |= CENTER;
		break;
	case 'r':
		*f &= ~ALIGN_MASK;
		*f |= RIGHT;
		break;
	default:
		fprintf(stderr, "alignment problem\n");
	}
}

 

C初级常见错误

 

char a[10];
怎么给这个数组赋值呢?
1、定义的时候直接用字符串赋值
char a[10]="hello";
注意:不能先定义再给它赋值,如char a[10]; a[10]="hello";这样是错误的!
2、对数组中字符逐个赋值
char a[10]={'h','e','l','l','o'};
3、利用strcpy
char a[10]; strcpy(a, "hello");

易错情况:
1、char a[10]; a[10]="hello";//一个字符怎么能容纳一个字符串?况且a[10]也是不存在的!
2、char a[10]; a="hello";//这种情况容易出现,a虽然是指针,但是它已经指向在堆栈中分配的10个字符空间,现在这个情况a又指向数据区中的hello常量,这里的指针a出现混乱,不允许!

还有:不能使用关系运算符“==”来比较两个字符串,只能用strcmp() 函数来处理。


C语言的运算符根本无法操作字符串。在C语言中把字符串当作数组来处理,因此,对字符串的限制方式和对数组的一样,特别是,它们都不能用C语言的运算符进行复制和比较操作。
直接尝试对字符串进行复制或比较操作会失败。例如,假定str1和str2有如下声明:

char str1[10], str2[10];

利用=运算符来把字符串复制到字符数组中是不可能的:

str1 = "abc";     /*** WRONG ***/

str2 = str1;       /*** WRONG ***/

C语言把这些语句解释为一个指针与另一个指针之间的(非法的)赋值运算。但是,使用=初始化字符数组是合法的:

char str1[10] = "abc";

这是因为在声明中,=不是赋值运算符。

试图使用关系运算符或判等运算符来比较字符串是合法的,但不会产生预期的结果:

if (str1==str2) ...    /*** WRONG ***/

这条语句把str1和str2作为指针来进行比较,而不是比较两个数组的内容。因为str1和str2有不同的地址,所以表达式str1 == str2的值一定为0。

 

 
下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;
 
  是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。

 

各进制之间的转换

 


一。进制概念 
 
1。 十进制 
 
十进制使用十个数字(0、1、2、3、4、5、6、7、8、9)记数,基数为10,逢十进一。 
 
历史上第一台电子数字计算机ENIAC是一台十进制机器,其数字以十进制表示,并以十进制形式运算。设计十进制机器比设计二进制机器复杂得多。而自然界具有两种稳定状态的组件普遍存在,如开关的开和关,电路的通和断,电压的高和低等,非常适合表示计算机中的数。设计过程简单,可靠性高。因此,现在改为二进制计算机。 
 
 
二。进制转换 
 
1。二进制与十进制数间的转换 
 
(1)二进制转换为十进制 
 
将每个二进制数按权展开后求和即可。请看例题: 
 
把二进制数 (101.101)2 = 1*$2^2+0*$2^1+1*$2^0+1*$2^{-1}+1*$2^{-3}=(5.625)10 
 
(2)十进制转换为二进制 
 
一般需要将十进制数的整数部分与小数部分分开处理。 
 
整数部分计算方法:除2取余法
(53)的二进制值为(110101)2
 
小数部分计算方法:乘2取整法,即每一步将十进制小数部分乘以2,所得积的小数点左边的数字(0或1)作为二进制表示法中的数字,第一次乘法所得的整数部分为最高位。请看例题: 
 
将 (0.95)10 转换成二进制。(0.95)10 =(0.1111....)2
 
2。 八进制、十六进制与十六进制间的转换 
 
八进制、十六进制与十六进制之间的转换方法与二进制,同十进制之间的转换方法类似。例如: 
 
(73)8     7*8+3= (59)10
 
(0.56)5*8-1+6*8-2=(0.71875)10
 
(12A)16=1*$16^{2}+2*$16^{1}+A*$16^{0}=(298)10 
 
(0.3C8)16=3*$16^{-1}+12*$16^{-2}+8*$16^{-3}=(0.142578125)10 
 
十进制整数→→→→→八进制方法:“除8取余” 
 
十进制整数→→→→→十六进制方法:“除16取余” 例如: 
 
(171)10=(253)8 
 
(2653)10=(A5D)16 
 
十进制小数→→→→→八进制小数 方法:“乘8取整” 
 
十进制小数→→→→→十六进制小数方法:“乘16取整”例如: 
 
(0.71875)10= (0.56)8
 
(0.142578125)10=(0.3C8)16
 
3.非十进制数之间的转换 
 
(1)二进制数与八进制数之间的转换 
 
转换方法是:以小数点为界,分别向左右每三位二进制数合成一位八进制数,或每一位八进制数展成三位二进制数,不足三位者补0。例如: 
 
(423.45)8= (100 010 011.100 101)2
 
(1001001.1101)2 =(001 001 001.110 100)2= (111.64)8
 
2。二进制与十六进制转换 
 
转换方法:以小数点为界,分别向左右每四位二进制合成一位十六进制数,或每一位十六进制数展成四位二进制数,不足四位者补0。例如: 
 
(ABCD.EF)16 = (1010 1011 1100 1101.1110 1111)2
 
(101101101001011.01101)2= (0101 1011 0100 1011.0110 1000)2 = (5B4B.68)16
 

多种类型菱形打印(初学代码,以后删除)

 

/*
 * =====================================================================================
 *       Filename:  diamond-1.c
 *    Description:  编写函数diamond打印一个菱形
 *			问题摘自 http://learn.akae.cn/media/ch06s05.html
 * =====================================================================================
 */

#include	<stdio.h>
#include	<stdlib.h>

void diamond(int n, char x)
{
	if (n % 2 == 0) {
		printf("wrong number\n");
		return;
	}

	int i, j;

	for (i = (-n / 2); i < (n / 2 + 1); ++i) {
		for (j = 0; j < n; ++j) {
			if (j < 2 * abs(i)) {
				if (j % 2 == 0)
					printf(" ");
				else
					printf("\t");
			} else
				printf("%c\t", x);
		}
		printf("\n");
	}

}

int main(void)
{
	diamond(5, '&');
	return 0;
}

 

/*
 * =====================================================================================
 *       Filename:  diamond-2.c
 *    Description:  打印如下所示的菱形,创建一个函数diamond2();
 *
    A
   BBB
  CCCCC
 DDDDDDD
  CCCCC
   BBB
    A
 *        Created:  2011年01月10日 23时45分54秒
 * =====================================================================================
 */
#include	<stdio.h>
#include	<stdlib.h>

void diamond2(int n)
{
// 因为要显示大写字母,范围在A-Z,所以n的取值范围为 3——2*26-1=51
	if (n % 2 == 0 && n < 3 && n >= 51) {
		printf("Wrong Number\n");
		return;
	}

	int i, j, k, charx;
	char x = 'A';

	for (i = n / 2; i > -(n / 2 + 1); --i) {
		for (j = 0; j < abs(i); ++j)
			printf(" ");
//当i大于0时,字符A先输出再自增:x++。 否则,--x-1。
		if (i >= 0)
			charx = x++;
		else
			charx = --x - 1;
		for (k = 0; k < n - 2 * abs(i); ++k) {
			printf("%c", charx);
		}
		printf("\n");
	}
}

int main(void)
{
//      测试最大菱形
	diamond2(51);
	return 0;
}

 

/*
 * ==========================================================================
 *
 *    Description:
 *    编写一个程序,读取输入,直到读了10个字符串或者遇到EOF。这个程序可以为用户提供一个有5个选项的菜单:

 1. 输出初始化字符串列表\n\
 2. 按ascii码顺序输出字符串\n\
 3. 按长度递增输出字符串\n\
 4. 按字符串中第一个单词的长度输出字符串\n\
 5. 退出\n
 *
 *        Version:  1.0
 *        Created:  2011年01月28日 00时17分41秒
 *       Revision:  none
 *       Compiler:  gcc
 * ==========================================================================
 */

//全用的选择排序算法
//尤其注意136行,不能是 if (strlen(v[i]) - strlen(v[j]) >
//0),必须是strlen(v[i]) >
//strlen(v[j]),因为strlen返回unsigned值,unsigned值相减返回unsigned值
//

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

#define MAXLINE 10		/* 最多输入字符串个数 */
#define MAXLEN 50		/* 字符串最大字符数 */

void menu(void);		/* 菜单显示程序 */
void prall(char *v[], int n);	/* 打印所有字符串 */
void compascii(char *s);	/* 按ascii码顺序输出字符串 */
void complen(char *v[], size_t lim);	/* 按字符串长度递增输出字符串 */
int cmpwd(char *s);		/* 计算单个字符串中第一个单词的长度 */
void compcmp(char *v[], size_t lim);	/* 按第一个长度排列所有字符串 */

int main(void)
{
	bool flags = true;	/* 菜单“退出”标记 */
	int c, i, j;
	size_t linenum = 0;	/* 实际输入的行数 */
	char a[MAXLINE][MAXLEN] = { 0 };
	char *p[MAXLINE];

	printf
	    ("请输入不超过10个字符串,每行字符串以换行符结尾\n");

	for (i = 0; i < MAXLINE; i++) {
		++linenum;
		j = 0;
		while (((c = getchar()) != '\n') && c != EOF && j < MAXLEN - 1)
			a[i][j++] = c;
		a[i][j] = '\0';
		if (c == EOF)
			break;
	}

	while (flags) {
		for (i = 0; i < linenum; i++)
			p[i] = a[i];
		menu();
		switch (c = getchar()) {
		case '1':
			prall(p, linenum);
			break;
		case '2':
			for (i = 0; i < linenum; ++i)
				compascii(a[i]);
			break;
		case '3':
			complen(p, linenum);
			prall(p, linenum);
			break;
		case '4':
			compcmp(p, linenum);
			prall(p, linenum);
			break;
		case '5':
			flags = false;
			break;
		default:
			printf
			    ("\n\n\n请输入1-5选择您要的功能,按5键推出\n");
			break;
		}
		while (getchar() != '\n') ;	/* 清除多余的回车符 */
	}

	return 0;
}

void menu(void)
{
	printf("按键1-5选择相应菜单\n\
1. 输出初始化字符串列表\n\
2. 按ascii码顺序输出字符串\n\
3. 按长度递增输出字符串\n\
4. 按字符串中第一个单词的长度输出字符串\n\
5. 退出\n");
}

void prall(char *v[], int n)
{

	int i;
	for (i = 0; i < n; i++) {
		printf("%s\n", v[i]);
	}
}

void compascii(char *s)
{
	char a[MAXLEN];
	int i, j, k;
	char temp;
	for (i = 0; i < MAXLEN - 1 && s[i] != '\0'; i++)
		a[i] = s[i];
	for (j = 0; j < i - 1; j++)
		for (k = j + 1; k < i; k++)
			if (a[j] > a[k]) {
				temp = a[j];
				a[j] = a[k];
				a[k] = temp;
			}
	a[i] = '\0';
	printf("%s\n", a);
}

void complen(char *v[], size_t lim)
{
	int i, j;
	char *temp;
	for (i = 0; i < lim - 1; i++)
		for (j = i + 1; j < lim; j++)
			if (strlen(v[i]) > strlen(v[j])) {
				temp = v[i];
				v[i] = v[j];
				v[j] = temp;
			}
}

int cmpwd(char *s)
{
	size_t num = 0;
	while (*s)
		if (!isspace(*s++))
			num++;
		else
			break;
	return num;
}

void compcmp(char *v[], size_t lim)
{
	int i, j;
	char *temp;
	for (i = 0; i < lim - 1; i++)
		for (j = i + 1; j < lim; j++)
			if (cmpwd(v[i]) > cmpwd(v[j])) {
				temp = v[i];
				v[i] = v[j];
				v[j] = temp;
			}
}

 

C程序设计语言(第二版)课后习题答案 4-6 章

/*
 * =====================================================================================
 *
 *       Filename:  4-1.c
 *
 *    Description:
 *    编写函数strrindex(s,t),他返回字符串t在s中最右边出现的位置。如果s中不包含t,则返回-1
 *
 *        Version:  1.0
 *        Created:  2011年01月08日 16时24分12秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Sd44 (), sd44sd44@yeah.net
 *       Homepage:  http://sd44.is-programmer.com
 *
 * ===================================================================================== 
 */

#include	<stdio.h>
int strrindex(char s[], char t[])
{
	int i, j, k, subnum = -1;  

	for (i = 0; s[i] != '\0'; ++i) {
		for (j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++) ;
 
		if (k > 0 && t[k] == '\0')
			subnum = i;
	}  
	return subnum;

}

int main(void)
{
	char a[] = "wo ha woai ni";
	char b[] = "wo";
	printf("%d\n", strrindex(a, b));
	return 0;

}

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

double atof(char s[])
{
	double val, power;
	int expnum;
	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;
	}
	val = sign * val / power;

	if (s[i] == 'e' || s[i] == 'E')
		++i;
	if (s[i] == '+') {
		++i;
		sign = 1;
	}
	if (s[i] == '-') {
		++i;
		sign = -1;
	}

	for (expnum = 0; isdigit(s[i]); ++i)
		expnum = 10 * expnum + (s[i] - '0');
	val = val * pow(10, sign * expnum);
	return val;
}

int main(void)
{
	char a[] = "123.45e-2";
	printf("%f\n", atof(a));
	return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#define MAXOP      100
#define NUMBER       0
/* 4-6 these are new for this exercise*/
#define IDENTIFIER   1
#define ENDSTRING    2
/* 4-6 end of new stuff */
#define TRUE         1
#define FALSE        0
#define MAX_ID_LEN  32
#define MAXVARS     30

/* 
The new additions deal with adding variables to the calculator.

  If the identifier is recognised as one of the supported mathematical 
  functions then that function from the library is called. If the 
  identifier is not one of the supported functions, even if it is a
  valid function from math.h it is ignored.
  
  This is a class 1 solution as it uses structures which are not 
  introduced until Chapter 6. This allows the use of "normal" names for
  variables rather than the suggested single letter though any 
  identifier is limited to 31 characters.
    
  The main changes are:
      
    1. The introduction of two more define values (IDENTIFIER, 
       ENDSTRING) along with associated cases in the switch statement. 
    2. Getop has also been changed to deal with reading in alphabetical 
       characters and coping with the '=' sign.
    3. A structure to hold the variable name and value.
    4. Another case in the switch statement to deal with the '=' sign.
    5. Altering the clearStack function to clear the array of structs as
       well as the stack.
    6. The '<' operator now prints the last accessed variable.
        
  Improvements:
  The code could be made class 0 by the use of "parallel" arrays for the
  names and values rather than a struct but this would be messy and is 
  the situation that structs were made for.
  The use of a binary tree together with dynamically allocated memory
  would allow the arbitrary limit of 30 variables to be avoided. This 
  would still be a class 1 solution. 
         
  This is exercise 4-6 from Kernighan & Ritchie, page 79.               
*/

/* 4-6 this is new for this program */
struct varType {
	char name[MAX_ID_LEN];
	double val;
};
/* 4-6 End of new stuff */

int Getop(char s[]);
void push(double val);
double pop(void);
void showTop(void);
void duplicate(void);
void swapItems(void);

/* 4-6 this is new for this program */
/* Changed clearStack(void) to clearStacks(struct varType var[])*/
void clearStacks(struct varType var[]);
void dealWithName(char s[], struct varType var[]);
void dealWithVar(char s[], struct varType var[]);

int pos = 0;
struct varType last;

/* 4-6 End of new stuff */

int main(void)
{
	int type;
	double op2;
	char s[MAXOP];
	struct varType var[MAXVARS];

	/* Use the new function here */
	clearStacks(var);

	while ((type = Getop(s)) != EOF) {
		switch (type) {
		case NUMBER:
			push(atof(s));
			break;
		case IDENTIFIER:
			dealWithName(s, var);
			break;
		case '+':
			push(pop() + pop());
			break;
		case '*':
			push(pop() * pop());
			break;
		case '-':
			op2 = pop();
			push(pop() - op2);
			break;
		case '/':
			op2 = pop();
			if (op2)
				push(pop() / op2);
			else
				printf("\nError: division by zero!");
			break;
		case '%':
			op2 = pop();
			if (op2)
				push(fmod(pop(), op2));
			else
				printf("\nError: division by zero!");
			break;
		case '?':
			showTop();
			break;
		case '#':
			duplicate();
			break;
		case '~':
			swapItems();
			break;
		case '!':
			clearStacks(var);
			break;
		case '\n':
			printf("\n\t%.8g\n", pop());
			break;
			/* 4-6 this is new for this program */
		case ENDSTRING:
			break;
		case '=':
			pop();
			var[pos].val = pop();
			last.val = var[pos].val;
			push(last.val);
			break;
		case '<':
			printf("The last variable used was: %s (value == %g)\n",
			       last.name, last.val);
			break;
			/* 4-6 End of new stuff */
		default:
			printf("\nError: unknown command %s.\n", s);
			break;
		}
	}
	return EXIT_SUCCESS;
}

#define MAXVAL 100

int sp = 0;			/* Next free stack position. */
double val[MAXVAL];		/* value stack. */

/* push: push f onto stack. */
void push(double f)
{
	if (sp < MAXVAL)
		val[sp++] = f;
	else
		printf("\nError: stack full can't push %g\n", f);
}

/*pop: pop and return top value from stack.*/
double pop(void)
{
	if (sp > 0) {
		return val[--sp];
	} else {
		printf("\nError: stack empty\n");
		return 0.0;
	}
}

void showTop(void)
{
	if (sp > 0)
		printf("Top of stack contains: %8g\n", val[sp - 1]);
	else
		printf("The stack is empty!\n");
}

/*
Alternatively:
void showTop(void)
{
double item = pop();
printf("Top of stack contains: %8g\n", item);
push(item);
}  
*/

void duplicate(void)
{
	double temp = pop();

	push(temp);
	push(temp);
}

void swapItems(void)
{
	double item1 = pop();
	double item2 = pop();

	push(item1);
	push(item2);
}

/* 4-6 this is new for this program */
/* Altered to clear both the main stack and that of the variable
structure */
void clearStacks(struct varType var[])
{
	int i;

	/* Clear the main stack by setting the pointer to the bottom. */
	sp = 0;

	/* Clear the variables by setting the initial element of each name
	   to the terminating character. */
	for (i = 0; i < MAXVARS; ++i) {
		var[i].name[0] = '\0';
		var[i].val = 0.0;
	}
}

/* a string/name may be either a maths function or a variable */
void dealWithName(char s[], struct varType var[])
{
	double op2;

	if (!strcmp(s, "sin"))
		push(sin(pop()));
	else if (!strcmp(s, "cos"))
		push(cos(pop()));
	else if (!strcmp(s, "exp"))
		push(exp(pop()));
	else if (!strcmp(s, "pow")) {
		op2 = pop();
		push(pow(pop(), op2));
	}
	/* Finally if it isn't one of the supported maths functions we have a 
	   variable to deal with. */
	else {
		dealWithVar(s, var);
	}
}

/* Our identifier is not one of the supported maths function so we have 
   to regard it as an identifier. */
void dealWithVar(char s[], struct varType var[])
{
	int i = 0;

	while (var[i].name[0] != '\0' && i < MAXVARS - 1) {
		if (!strcmp(s, var[i].name)) {
			strcpy(last.name, s);
			last.val = var[i].val;
			push(var[i].val);
			pos = i;
			return;
		}
		i++;
	}

	/* variable name not found so add it */
	strcpy(var[i].name, s);
	/* And save it to the last variable */
	strcpy(last.name, s);
	push(var[i].val);
	pos = i;
}

/* 4-6 End of new stuff */

int getch(void);
void unGetch(int);

/* Getop: get next operator or numeric operand. */
int Getop(char s[])
{
	int i = 0;
	int c;
	int next;

	/* Skip whitespace */
	while ((s[0] = c = getch()) == ' ' || c == '\t') {
		;
	}
	s[1] = '\0';

	if (isalpha(c)) {
		i = 0;
		while (isalpha(s[i++] = c)) {
			c = getch();
		}
		s[i - 1] = '\0';
		if (c != EOF)
			unGetch(c);
		return IDENTIFIER;
	}

	/* Not a number but may contain a unary minus. */
	if (!isdigit(c) && c != '.' && c != '-') {
		/* 4-6 Deal with assigning a variable. */
		if ('=' == c && '\n' == (next = getch())) {
			unGetch('\0');
			return c;
		}
		if ('\0' == c)
			return ENDSTRING;

		return c;
	}

	if (c == '-') {
		next = getch();
		if (!isdigit(next) && next != '.') {
			return c;
		}
		c = next;
	} else {
		c = getch();
	}

	while (isdigit(s[++i] = c)) {
		c = getch();
	}
	if (c == '.') {		/* Collect fraction part. */
		while (isdigit(s[++i] = c = getch())) ;
	}
	s[i] = '\0';
	if (c != EOF)
		unGetch(c);
	return NUMBER;
}

#define BUFSIZE 100

int buf[BUFSIZE];
int bufp = 0;

/* Getch: get a ( possibly pushed back) character. */
int getch(void)
{
	return (bufp > 0) ? buf[--bufp] : getchar();
}

/* unGetch: push character back on input. */
void unGetch(int c)
{
	if (bufp >= BUFSIZE)
		printf("\nUnGetch: too many characters\n");
	else
		buf[bufp++] = c;
}
#include <stdio.h>
#include	<string.h>

#define	BUFSIZE 100		/*  */
char buf[BUFSIZE];
int bufp = 0;

int getch(void)
{
	return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c)
{
	if (bufp >= BUFSIZE)
		printf("ungetch: too many character\n");
	else
		buf[bufp++] = c;
}

void ungets(char s[])
{
	size_t i = strlen(s);
	while (i--)
		ungetch(s[i]);
}

int main(void)
{
	int c;
	char s[] = "wo ai bei jing tian an men";
	ungets(s);
	while ((c = getch()) != EOF)
		putchar(c);
	return 0;
}
#include <stdio.h>

int bufp = EOF;

int getch(void)
{
	int temp;
	if (bufp != EOF) {
		temp = bufp;
		bufp = EOF;
	} else
		temp = getchar();
	return temp;
}

void ungetch(int c)
{
	bufp = c;
}

int main(void)
{
	char c = 's';
	ungetch(c);
	putchar(getch());
	return 0;
}
//此程序做完后,参考网上答案,自己写的函数不够规范,两个函数都不完整,必须借助于另一个函数来实现一个功能
// 例如http://www.dnbcw.com/biancheng/c/leku175858.html 中所介绍的,'\0'是直接在单个函数中通过 if (value < (unsigned) base) else 加入的。。。

#include	<stdio.h>
void _itoa(int n, char *s)
{
	if (n / 10)
		_itoa(n / 10, s - 1);
	*s = n % 10 + '0';
}

void itoa(int n, char *s)
{
	int x, digit = 0;	/*digit为整数n的位数 */

	if (n < 0) {		/* 如果n为负数,数组首位为 '-' */
		n = -n;
		*s++ = '-';
	}

	x = n;			/* 求n的位数digit */
	do {
		++digit;
	} while (x /= 10);

	_itoa(n, s + digit - 1);	/* 递归调用_itoa */
	*(s + digit) = '\0';	/* 转换完成后,结尾 */
}

int main(void)
{
	char a[10];
	itoa(-231456, a);
	printf("%s\n", a);                 
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  4-13.c
 *
 *    Description:  reverse(s)递归版本
 *
 *        Version:  1.0
 *        Created:  2011年01月13日 13时20分49秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include	<stdio.h>
#include	<string.h>
void swap(char *a, char *b)
{
	char temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

void reverse(char *s, unsigned int len)
{
	if (len <= 1)
		return;
	swap(s, s + len - 1);
	reverse(s + 1, len - 1 - 1);
}

int main(int argc, char *argv[])
{
	char a[] = "tian an men, wo ai ni";
	reverse(a, strlen(a));
	printf("%s\n", a);
	return 0;
}
#define swap(t,x,y) do{t z=x;x=y;y=z;}while(0)

do while既保持良好的程序块格式,又不会因为 ;号而影响易读性

 

#include	<stdio.h>
#include	<ctype.h>
#include	"getch.c"

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

int getfloat(double *pn)
{
	int c, sign, flag = 0;
	double power = 1.0;

	while (isspace(c = getch())) ;
	if (!isdigit(c) && c != EOF && c != '+' && c != '-' && c != '.') {
		ungetch(c);
		return 0;
	}
	sign = (c == '-') ? -1 : 1;
	if (c == '+' || c == '-') {
		flag = c;
		c = getch();
	}
	if (!isdigit(c) && c != '.') {
		ungetch(c);
		if (flag)
			ungetch(flag);
		return 0;
	}

	for (*pn = 0.0; isdigit(c); c = getch())
		*pn = 10.0 * *pn + (c - '0');

	if (c == '.')
		while (isdigit(c = getch())) {
			*pn = 10.0 * *pn + (c - '0');
			power *= 10.0;
		}
	*pn *= sign;
	*pn /= power;

	if (c != EOF)
		ungetch(c);
	return c;
}

 

/*
 *       Filename:  5-3.c
 *
 *    Description:  用指针实现strcat(s,t)
 *
 *        Version:  1.0
 *        Created:  2011年01月14日 00时10分37秒
 *
 * ==========================================================================
 */
#include	<stdio.h>

char *strcat(char *s, char *t)
{
	char *p = s;
	while (*s++) ;
	s--;
	while (*s++ = *t++) ;
	return p;
}

int main(void)
{
	char a[100] = " lao po,jia you. ";
	char b[] = " zi mo, ye jia you ";
	printf("%s \n", strcat(a, b));
	return 0;
}

 

/*
 * ==========================================================================
 *
 *       Filename:  5-4.c
 *
 *    Description:  strend(s,t),如果字符串t出现在字符串s尾部,返回1
 *
 *        Version:  1.0
 *        Created:  2011年01月14日 01时09分42秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include	<stdio.h>
#include	<string.h>
int strend(char *s, char *t)
{
	size_t x, y;
	x = strlen(s);
	y = strlen(t);

	for (; x > 0 && y > 0 && *(s + x - 1) == *(t + y - 1); x--, y--) ;
	if (y == 0)
		return 1;
	else
		return 0;
}

int main(void)
{
	char a[] = "nasa damn";
	char b[] = "damn";
	printf("%d\n", strend(a, b));
	return 0;
}

 

// strncmp的创建有点费时
#include	<stdio.h>

void strncpy2(char *s, char *t, size_t n)
{
	while (n--)
		*s++ = *t++;
	*s = '\0';
}

char *strncat(char *s, char *t, size_t n)
{
	char *p = s;
	while (*s++) ;
	s--;
	while (n--)
		*s++ = *t++;
	return p;
}

int strncmp(char *s, char *t, size_t n)
{
	while (n--) {
		if (*s == '\0' || *t == '\0')	/*防止指针越界 */
			return *s - *t;
		if (*s++ != *t++)
			return *--s - *--t;	/* 返回不相等字符的差 */
	}
	return 0;
}

int main(void)
{
	char a[100] = " lao po,jia you. ";
	char b[] = "zi mo, ye jia you ";
	printf("%s \n", strncat(a, b, 5));
	strncpy2(a, b, 5);
	printf("%s \n", a);
	printf("%d\n", strncmp(a, b, 8));

	char c[5] = "haha ";
	char d[5] = "haha";
	printf("%d\n", strncmp(c, d, 6));
	return 0;
}

 

#include	<stdio.h>
#include	<string.h>
#include	"getch.c"

#define	MAXLINES 5000		/*  */
#define	MAXLEN 1000		/*  */

int getline2(char *, int);
int readlines(char lineptr[][MAXLEN], int maxlines)
{				/* 二维数组做形参,第二维必须是常量 */
	int len, nlines = 0;

	while ((len = getline2(lineptr[nlines], MAXLEN)) > 0)	/* 注意此时getline2的形参 */
		if (nlines >= MAXLINES)
			return -1;
		else {
			lineptr[nlines][len - 1] = '\0';	/* 去掉换行符 */
			nlines++;
		}
	return nlines;
}

void writelines(char *lineptr[], int nlines)
{
	int i;

	for (i = 0; i < nlines; i++)
		printf("%s\n", lineptr[i]);
}

void qsort2(char *v[], int left, int right)
{
	int i, last;
	void swap(char *v[], int i, int j);

	if (left >= right)
		return;
	swap(v, left, (left + right) / 2);
	last = left;
	for (i = left + 1; i <= right; i++)
		if (strcmp(v[i], v[left]) < 0)
			swap(v, ++last, i);
	swap(v, left, last);
	qsort2(v, left, last - 1);
	qsort2(v, last + 1, right);
}

void swap(char *v[], int i, int j)
{
	char *temp;
	temp = v[i];
	v[i] = v[j];
	v[j] = temp;
}

int main(int argc, char *argv[])
{
	int nlines, backnlines;
	char linearr[MAXLINES][MAXLEN];
	char *lineptr[MAXLINES];

	if ((nlines = readlines(linearr, MAXLINES)) >= 0) {
		backnlines = nlines;
		while (backnlines--)
			lineptr[backnlines] = linearr[backnlines];
		qsort2(lineptr, 0, nlines - 1);
		writelines(lineptr, nlines);
		return 0;
	} else {
		printf("error: input too big to sort\n");
		return 1;
	}
}				/* ----------  end of function main  ---------- */

int getline2(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') {
		s[i++] = c;
	}
	s[i] = '\0';
	return i;
}

 

C程序设计语言(第二版)课后习题答案 1-3 章

K&R C 课后题答案,有不完善的地方还请诸位大虾多多指评!

/*
 * ==========================================================================
 *
 *       Filename:  1-6-7.c
 *
 *    Description:  验证表达式getchar()!=EOF 的值是0还是1
 *		    编写一个打印EOF值的程序
 *
 *        Version:  1.0
 *        Created:  2010年12月29日 13时07分03秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

int main(void)
{
	printf("%d\n", getchar() != EOF);
	printf("%d\n", EOF);
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-8.c
 *
 *    Description:  编写一个统计空格、制表符与换行符个数的程序
 *
 *        Version:  1.0
 *        Created:  2010年12月29日 13时12分21秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>

int main(void)
{
	int c;
	int snum, tnum, nnum;

	snum = tnum = nnum = 0;

	while ((c = getchar()) != EOF) {
		if (c == ' ')
			++snum;
		if (c == '\t')
			++tnum;
		if (c == '\n')
			++nnum;
	}
	printf
	    ("您所输入的字符串中\n 共有空格 %d 个,制表符 %d 个, 换行符 %d 个\n ",
	     snum, tnum, nnum);
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-9.c
 *
 *    Description:  将输入复制到输出,并将其中连续的多个空格用一个空格代替
 *
 *        Version:  1.0
 *        Created:  2010年12月29日 13时20分54秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

int main(void)
{
	int flags = 1;
	int c;

	while ((c = getchar()) != EOF) {
		if (c == ' ') {
			if (flags == 1)
				putchar(' ');
			flags = 0;
		} else {
			putchar(c);
			flags = 1;
		}
	}
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-10.c
 *
 *    Description:  制表符替换为\t,回退符替换为\b,反斜杠替换为\\
 *
 *        Version:  1.0
 *        Created:  2010年12月29日 13时33分13秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

#define ESC_CHAR '\\'

int main(void)
{
	int c;

	while ((c = getchar()) != EOF) {
		switch (c) {
		case '\b':
			putchar(ESC_CHAR);
			putchar('b');
			break;
		case '\t':
			putchar(ESC_CHAR);
			putchar('t');
			break;
		case ESC_CHAR:
			putchar(ESC_CHAR);
			putchar(ESC_CHAR);
			break;
		default:
			putchar(c);
			break;
		}
	}
	return 0;
}

1-11不懂

/*
 * ==========================================================================
 *
 *       Filename:  1-12.c
 *
 *    Description:  编写一个程序,以每行一个单词的形式打印其输入
 *
 *        Version:  1.0
 *        Created:  2010年12月29日 13时44分29秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

int main(void)
{
	int c;
	int flags = 1;
	while ((c = getchar()) != EOF) {
		if (c == ' ' || c == '\n' || c == '\t') {
			if (flags)
				putchar('\n');
			flags = 0;
		} else {
			putchar(c);
			flags = 1;
		}

	}
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-13.c
 *
 *    Description:  编写一个程序,打印输入中单词长度的直方图
 *
 *        Version:  1.0
 *        Created:  2010年12月31日 21时28分46秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

int isspace2(int c)
{
	if (c == ' ' || c == '\n' || c == '\t')
		return 1;
	else
		return 0;
}

int main(void)
{
	int c;

	while ((c = getchar()) != EOF)
		if (!isspace2(c))
			putchar('*');
		else
			putchar('\n');

	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-13.c
 *
 *    Description:  编写一个程序,打印输入中单词长度的直方图(垂直直方图)
 *
 *        Version:  1.0
 *        Created:  2010年12月31日 21时28分46秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>
#include <ctype.h>
#define MAXWORDS 20 //单词最大数量

int main(void)
{
	int c, j, maxlen = 0, i = 0, n = 0;  //maxlen为最长长度, i为数组长度,n为单个单词长度
	int a[MAXWORDS];

	while ((c = getchar()) != EOF)
		if (!isspace(c))
			++n;
		else {
			if (maxlen < n)
				maxlen = n;
			a[i++] = n;
			n = 0;
		}

	while (maxlen--) {
		for (j = 0; j < i; ++j)
			if ((a[j])-- > 0)
				putchar('*');
			else
				putchar(' ');
		putchar('\n');
	}

	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-14.c
 *
 *    Description:  打印输入中各个字符出现频度的直方图
 *
 *        Version:  1.0
 *        Created:  2010年12月31日 23时42分44秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

int main(void)
{
	int c, i = 0;
	int a[95];		//除去不可显示字符1-31,127
	for (i = 0; i < 95; ++i)
		a[i] = 0;

	while ((c = getchar()) != EOF)
		if ((c = getchar()) > 31 && (c = getchar()) < 127)
			++a[c - 32];
	for (i = 0; i < 95; ++i) {
		printf("%-5c", i + 32);
		while (a[i] > 0) {
			putchar('*');
			--a[i];
		}
		printf("\n");

	}
	return 0;
}
#include <stdio.h>

#define MAXLINE 1000		//允许的输入行的最大长度

int main(void)
{
	int c, i, j = 0, sptabnum = 0, tabnum = 0;	//sptabnum记录空格或Tab数目,tabnum记录空格数目
	char line[MAXLINE];

	for (i = 0; i < MAXLINE && (c = getchar()) != EOF; ++i) {
		line[j++] = c;
		if (c == '\n') {
			j = j - sptabnum - 1;
			line[j] = '\0';   //删除每个输入行末尾的空格及制表符
			if ((j + tabnum) > 0)	//如果输入行不完全是空格或者非空
				printf("%s\n", line);
			j = sptabnum = tabnum = 0;
		} else if (c == '\t') {
			++tabnum;
			++sptabnum;
		} else if (c == ' ')
			++sptabnum;
		else {
			sptabnum = 0;
			tabnum = 0;
		}
	}

/*如果输入字符为EOF,显示之前输入的行内容 */
	if (c == EOF) {
		line[j] = '\0';
		printf("\n%s", line);
	}

	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-19.c
 *
 *    Description:  reverse(s)
 *
 *        Version:  1.0
 *        Created:  2011年01月01日 13时08分11秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

void reverse(char s[])
{
	int j, temp, i;
	i = j = 0;
	while (s[i++]) ;	//结果i为字符串S长度,包括\0

	i = i - 2;		//此时i为字符串s中最后一个字符下标
	while (j < i) {
		temp = s[j];
		s[j++] = s[i];
		s[i--] = temp;
	}
}

int main(void)
{
	char s[] = "wo ai ni,lao po";
	reverse(s);
	printf("%s\n", s);
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-20.c
 *
 *    Description:
 *    将输入中的制表符替换成适当数目的空格,使空格充满到下一个制表符终止位的地方。
 *
 *        Version:  1.0
 *        Created:  2011年01月01日 16时52分57秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

void detab(void)
{
	int tabnum = 0, c;

	while ((c = getchar()) != EOF) {
		if (c == '\t') {
			++tabnum;
			printf("        ");	//tabsize为8个字符
		} else if (tabnum == 0)
			putchar(c);
		else if (tabnum > 0)
			putchar(' ');
		if (tabnum == 2)
			tabnum = 0;
	}
}

int main(void)
{
	detab();
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  1-21.c
 *
 *    Description:  编写程序entab,
 *    将空格串替换为最少数量的制表符和空格,但要保持单词之间的间隔不变。
 *
 *        Version:  1.0
 *        Created:  2011年01月01日 22时03分56秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>
#include <string.h>

#define TABSIZE 4

void entab(char s[])
{
	int i, j, k = 0, spnum = 0;

	for (i = 0; i < strlen(s); ++i, ++k)
		if (s[i] == ' ')
			++spnum;
		else {
			k -= spnum;
			for (j = spnum / TABSIZE; j > 0; --j) {
				s[k++] = '\t';
			}
			for (j = spnum % TABSIZE; j > 0; --j) {
				s[k++] = ' ';
			}
			s[k] = s[i];
			spnum = 0;
		}
	s[k] = '\0';
}

int main(void)
{
	char a[] = "wo        ai ni";
	printf("%d\n", strlen(a));

	entab(a);
	printf("%s\n", a);
	printf("%d\n", strlen(a));
	return 0;
}
未完成
未完成
未完成
/*
 * ==========================================================================
 *
 *       Filename:  2-3.c
 *
 *    Description:
 *    编写函数htoi(s),把十六进制数字组成的字符串(包括可选的前缀0X或0x)转换为与之等价的整形值。
 *
 *        Version:  1.0
 *        Created:  2011年01月01日 22时23分58秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>

int htoi(char hexstr[])
{
	int i = 0, tmp, result = 0, hexg = 0;
	if (hexstr[i] == '0' && (hexstr[i + 1] == 'x' || hexstr[i + 1] == 'X'))
		i = 2;
	while (hexstr[i]) {
		tmp = hexstr[i];
		if (tmp >= '0' && tmp <= '9')
			hexg = tmp - '0';
		else if (tmp >= 'a' && tmp <= 'f')
			hexg = tmp - 'a' + 10;
		else if (tmp >= 'A' && tmp <= 'F')
			hexg = tmp - 'A' + 10;
		else {
			printf("Your input is error\n");
			result = 0;
			break;
		}
		result = result * 16 + hexg;
		i++;
	}
	return result;
}

int main(void)
{
	char a[] = "0xF56";
	printf("%d\n", htoi(a));
	return 0;

}
/*
 * ==========================================================================
 *
 *       Filename:  2-4.c
 *
 *    Description:
 *    编写函数squeeze(s1,s2),将字符串s1中任何与字符串s2中字符匹配的字符都删除
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 10时01分49秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

#include <stdio.h>

void squeeze(char s1[], char s2[])
{
	int i, j, k, eqnum = 0;

	for (i = k = 0; s1[i] != '\0'; i++) {
		for (j = 0; s2[j] != '\0'; j++)
			if (s1[i] == s2[j])
				++eqnum;
		if (eqnum == 0)
			s1[k++] = s1[i];
		eqnum = 0;
	}
	s1[k] = '\0';
}

int main(void)
{
	char a[] = "sunbin";
	char b[] = "hankangli";
	squeeze(a, b);

	printf("%s\n", a);
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  2-5.c
 *
 *    Description: 编写函数any(s1,s2),将字符串s2中的任一字符在字符串s1中第一次出现的位置作为结果返回。如果s1中不包含s2中的字符,则返回-1
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 10时14分54秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

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

int any(char s1[], char s2[])
{
	int i, j;

	for (i = 0; s1[i] != '\0'; ++i)
		for (j = 0; s2[j] != '\0'; ++j) {
			if (s1[i] == s2[j])
				return j;
		}

	return -1;
}

int main(void)
{
	char a[] = "shit";
	char b[] = "fucking";

	printf("%d\n", any(a, b));
	printf("%c\n", *strpbrk(a, b));
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  2-6.c
 *
 *    Description:  编写一个函数setbits(x,p,n,y),该函数返回对x执行下列操作后
 *			的结果值:将x从第p位开始的n个二进制位设置为y中最右边n
 *			位的值,x的其余各位保持不变
 *        Version:  1.0
 *        Created:  2011年01月02日 10时45分20秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>

int setbits(int x, int p, int n, int y)
{
	return (x >> (p - n + 1) & ~(~0 << n)) | (y >> n << n);
}

int main(void)
{
	int a = 89;
	int b = 89;
	printf("%d\n", setbits(a, 4, 3, b));
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  2-7.c
 *
 *    Description:  编写一个函数invert(x,p,n),该函数返回对x执行下列操作后的
 *	      结果值:将x中从第p位开始的n个二进制位求反,x的其余各位保持不变
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 11时08分11秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>

int invert(unsigned int x, int p, int n)
{
	return x ^ ((~0 >> (p + 1 - n)) & ~(~0 << n) << (p + 1 - n));
}

int main(void)
{
	printf("%d", invert(156, 4, 3));
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  2-8.c
 *
 *    Description:
 *    编写一个函数rightrot(x,n),该函数返回将x循环右移(即从最右端移出的位将从最左端移入)n位后所得到的值
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 14时40分38秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>
#include <limits.h>

int rightrot(unsigned int x, int n)
{
	int y;			//y为x所移出N位的值
	y = x & ~(~0 << n);

	return x >> n | (y << (sizeof(x) * CHAR_MAX - n));
}

int main(void)
{
	printf("%d\n", rightrot(51, 2));
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  2-9.c
 *
 *    Description:  重写bitcount函数
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 17时59分43秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>

int bitcount(unsigned x)
{
	int b;
	for (b = 0; x != 0; x &= (x - 1))
		b++;
	return b;
}

int main(void)
{
	printf("%d\n", bitcount(50));
	return 0;
}
int binsearch2(int x, int v[], int n)
{
	int low, high, mid;

	low = 0;
	high = n - 1;
	mid = (low + high) / 2;
	while (low <= high && x != v[mid]) {
		if (x < v[mid])
			high = mid - 1;
		else
			low = mid + 1;
		mid = (low + high) / 2;
	}
	if (x == v[mid])
		return mid;
	else
		return -1;
}
/*
 * ==========================================================================
 *
 *       Filename:  3-2.c
 *
 *    Description:  编写一个函数escape(s,t),
 *    将字符串t复制到字符串s中,并在复制过程中将换行符、指标符等不可见字符分别转换为\n、\t等相应的可见的转移字符序列
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 18时51分17秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>
#include <string.h>

void escape(char s[], char t[])
{
	int i = 0, j = 0;
	while (t[i] != EOF) {
		switch (t[i]) {
		case '\n':
			s[j++] = '\\';
			s[j++] = 'n';
			break;
		case '\t':
			s[j++] = '\\';
			s[j++] = 't';
			break;
		default:
			s[j++] = t[i];
			break;
		}
		++i;
	}
	s[j] = EOF;
}

int main(void)
{
	char s[50];
	char t[20] = "wo ai			\n\n haha";
	escape(s, t);
	printf("%s\n", s);
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  3-2.c
 *
 *    Description:  编写一个函数escape(s,t),
 *    将字符串t复制到字符串s中,并在复制过程中将换行符、指标符等不可见字符分别转换为\n、\t等相应的可见的转移字符序列
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 18时51分17秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */
#include <stdio.h>

void escape2(char s[], char t[])
{
	int i = 0, j = 0, k = 0;
	while (t[i] != EOF) {
		switch (t[i]) {
		case '\\':
			++k;
			break;
		case 't':
			if (k == 1)
				s[j++] = '\t';
			k = 0;
			break;
		case 'n':
			if (k == 1)
				s[j++] = '\n';
			k = 0;
			break;
		default:
			for (; k > 0; --k)
				s[j++] = '\\';
			s[j++] = t[i];
			k = 0;
			break;
		}
		++i;
	}
	s[j] = EOF;
}

int main(void)
{
	char s[50];
	char t[30] = "lao \\t po\\n \\t \\t ha \\n haha";
	escape2(s, t);
	printf("%s\n", s);
	return 0;
}
/*
 * ==========================================================================
 *
 *       Filename:  3-3.c
 *
 *    Description:
 *    编写函数expand(s1,s2),将字符串s1中类似于a-z一类的速记符号在字符串s2中扩展为等价的完整列表abc..xyz.该函数可以处理大小写字符和数字,并可以处理a-b-c,a-z,0-9与a-z等类似的情况。作为前导和未遂的-字符原样排印。
 *
 *        Version:  1.0
 *        Created:  2011年01月02日 20时52分01秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  SD44 (), sd44sd44@yeah.net
 *        Company:  http://sd44.is-programmer.com/
 *
 * ==========================================================================
 */

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

void expand(char s1[], char s2[])
{
	int i, j, k, stag;
	i = j = 0;

	for (i = 0; s1[i] != '\0'; i++) {

		if (s1[i] == '-' && islower(s1[i - 1]) && islower(s1[i + 1])
		    && ((s1[i + 1] - s1[i - 1]) > 0)) {
			stag = s1[i - 1];
			k = s1[i + 1] - s1[i - 1] - 1;
			while (k--)
				s2[j++] = ++stag;
		} else if (s1[i] == '-' && isupper(s1[i - 1])
			   && isupper(s1[i + 1])
			   && ((s1[i + 1] - s1[i - 1]) > 0)) {
			stag = s1[i - 1];
			k = s1[i + 1] - s1[i - 1] - 1;
			while (k--)
				s2[j++] = ++stag;
		} else
		    if (s1[i] == '-' && isdigit(s1[i - 1]) && isdigit(s1[i + 1])
			&& ((s1[i + 1] - s1[i - 1]) > 0)) {
			stag = s1[i - 1];
			k = s1[i + 1] - s1[i - 1] - 1;
			while (k--)
				s2[j++] = ++stag;
		} else
			s2[j++] = s1[i];
	}
	s2[j] = '\0';
}

int main(void)
{
	char a[] = "h-a-hazz 3-9-5  3-A- ";
	char b[100];
	expand(a, b);

	printf("%s\n", b);
	return 0; 
}
/*
 * =====================================================================================
 *
 *       Filename:  3-4.c
 *
 *    Description:
 *    修改itoa函数,使其能够处理最大的负数,即n等于-2(n-1次方)的情况
 *
 *        Version:  1.0
 *        Created:  2011年01月08日 15时30分35秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Sd44 (), sd44sd44@yeah.net
 *       Homepage:  http://sd44.is-programmer.com
 *
 * =====================================================================================
 */

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

void reverse(char a[])
{
	int c, i, j;
	for (i = 0, j = strlen(a) - 1; i < j; i++, j--) {
		c = a[i];
		a[i] = a[j];
		a[j] = c;
	}
}

void itoa(int n, char s[])
{
	int i, sign;
	sign = n;

	i = 0;
	do {
		s[i++] = abs(n % 10) + '0';
	} while (n /= 10);

	if (sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}

int main(void)
{
	char b[50];
	itoa(-2147483647, b);
	printf("%s\n", b);
	return 0;
}

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

void reverse(char a[])
{
	int c, i, j;
	for (i = 0, j = strlen(a) - 1; i < j; i++, j--) {
		c = a[i];
		a[i] = a[j];
		a[j] = c;
	}
}

void itoa(int n, char s[])
{
	int i, sign;
	sign = n;

	i = 0;
	do {
		s[i++] = abs(n % 10) + '0';
	} while (n /= 10);

	if (sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}

int main(void)
{
	char b[50];
	itoa(-2147483647, b);
	printf("%s\n", b);
	return 0;
}

 

/*
 * =====================================================================================
 *
 *       Filename:  3-6.c
 *
 *    Description:
 *    itoa函数,使得该函数可以接收三个参数,其中,第三个参数为最小字段宽度。
 *
 *        Version:  1.0
 *        Created:  2011年01月08日 15时55分08秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Sd44 (), sd44sd44@yeah.net
 *       Homepage:  http://sd44.is-programmer.com
 *
 * =====================================================================================
 */
#include    <stdio.h>
#include    <string.h>

void reverse(char a[])
{
	int c, i, j;

	for (i = 0, j = strlen(a) - 1; i < j; i++, j--) {
		c = a[i];
		a[i] = a[j];
		a[j] = c;
	}
}

void itoa(int n, char s[], int width)
{
	int i, sign, temp = n, widnum = 0;
	if ((sign = n) < 0)
		n = -n;

	i = 0;
	do {
		s[i++] = n % 10 + '0';
		++widnum;	// widnum为整数n的位数
	} while (n /= 10);

	if (sign < 0) {
		s[i++] = '-';
//      如果n为负数,则宽度+1
		++widnum;
	}

	for (temp = width - widnum; temp > 0; --temp)
		s[i++] = ' ';

	s[i] = '\0';
	reverse(s);
}

int main(void)
{
	char b[50];
	itoa(-100, b, 8);
	printf("%s\n", b);
	return 0;
}

 

入门排序算法(逐步更新)

/*交换排序的基本思想是:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。 
应用交换排序基本思想的主要排序方法有:冒泡排序和快速排序。*/

/*  冒泡排序
 *   */

#include <stdio.h>

void bubble_sort(int *x, int n)
{
	int i, j, exchange, temp;	//用exchange保存交换标志
	for (i = n - 1; i > 0; i--) {	//冒泡算法最多做n-1趟排序
		exchange = 0;	//本趟排序开始前,交换标志应为假
		for (j = 0; j < i; j++)	//预置k=0,循环扫描后更新
			if (*(x + j) > *(x + j + 1)) {
				temp = *(x + j);
				*(x + j) = *(x + j + 1);
				*(x + j + 1) = temp;
				exchange = 1;	//发生交换,置标志为1
			}
		if (!exchange)	//如果未发生交换,退出
			return;
	}  
}

int main(void)
{
	int i;
	int a[5] = { 5, 3, 2, -5, 1 };
	bubble_sort(a, 5);
	for (i = 0; i < 5; i++)
		printf("%d ", a[i]);
	return 0;
}
#include <stdio.h>

void select_sort(int a[], int n)
{
	int i, j, temp, iMin;
	for (i = 0; i < n - 1; ++i) {
		iMin = i;
		for (j = i + 1; j < n; ++j)
			if (a[j] < a[iMin])
				iMin = j;
		if (iMin != i)
			temp = a[i], a[i] = a[iMin], a[iMin] = temp;
	}
}
static void merge(int array[], int low, int mid, int high)
{
	int i, k;
	int *temp = (int *) malloc((high-low+1) * sizeof(int)); //申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
	int begin1 = low;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = high;
 
	for (k = 0; begin1 <= end1 && begin2 <= end2; ++k)  //比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
		if(array[begin1]<=array[begin2])
			temp[k] = array[begin1++];
		else
			temp[k] = array[begin2++];	
	if(begin1 <= end1) //若第一个序列有剩余,直接拷贝出来粘到合并序列尾
		memcpy(temp+k, array+begin1, (end1-begin1+1)*sizeof(int));
	if(begin2 <= end2) //若第二个序列有剩余,直接拷贝出来粘到合并序列尾
		memcpy(temp+k, array+begin2, (end2-begin2+1)*sizeof(int));
        memcpy(array+low, temp, (high-low+1)*sizeof(int));//将排序好的序列拷贝回数组中
	free(temp);
}


void merge_sort(int array[], unsigned int first, unsigned int last)
{
	int mid = 0;
	if(first<last)
	{
		mid = (first+last)/2;
		merge_sort(array, first, mid);
		merge_sort(array, mid+1,last);
		merge(array,first,mid,last);
	}
}
/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  SHELLSORT
 *  Description:  Donald Shell 最初建议步长选择为n/2并且对步长取半直到步长达到1。虽然这样取可以比O(n2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。 可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。
步长序列 	最坏情况下复杂度
n / 2i 	\mathcal{O}(n2)
2k − 1 	\mathcal{O}(n3 / 2)
2i3i 	\mathcal{O}(nlog2n)

已知的最好步长序列由Marcin Ciura设计(1,4,10,23,57,132,301,701,1750,…) 这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。

另一个在大数组中表现优异的步长序列是(斐波那契数列除去0和1将剩余的数以黄金分割比的两倍的幂进行运算得到的数列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …)[2]
 * =====================================================================================
 */
#include 	<stdio.h>
#include	<stdlib.h>

void shellsort(int data[], int n)
{
	int gap, i, j, temp;

	for (gap = n / 2; gap > 0; gap /= 2)
		for (i = gap; i < n; i++)
			for (j = i - gap; j >= 0 && data[j] > data[j + gap];
			     j -= gap) {
				temp = data[j];
				data[j] = data[j + gap];
				data[j + gap] = temp;
			}
}

int main(void)
{
	int a[] = { 53, 325, 456, 24352, 2345, 32, 234, 23, 21, 2, 3, 4325 };
	shellsort(a, 12);
	for (int i = 0; i < 12; i++)
		printf("%d\t", a[i]);
	return EXIT_SUCCESS;
}
#include 	<stdio.h>
#include	<stdlib.h>

void swap(int v[], int i, int j)
{
	int temp = v[i];
	v[i] = v[j];
	v[j] = temp;
}

void qsort1(int v[], int left, int right)
{
	int i, last;
	if (left >= right)
		return;
	swap(v, left, (left + right) / 2);
	last = left;
	for (i = left + 1; i <= right; i++)
		if (v[i] < v[left])
			swap(v, ++last, i);
	swap(v, left, last);
	qsort1(v, left, last - 1);
	qsort1(v, last + 1, right);
}
void InsertSort(char array[], unsigned int n)
{
	int i, j;
	int temp;
	for (i = 1; i < n; i++) {
		temp = array[i];	//store the original sorted array in temp
		for (j = i; j > 0 && temp < array[j - 1]; j--)	//compare the new array with temp(maybe -1?)
		{
			array[j] = array[j - 1];	//all larger elements are moved one pot to the right
			array[j - 1] = temp;
		}
	}
}

 

C最初级知识


#include <stdio.h>
int main(void)
{
	int a, b, c;
	b = 5;
	c = 5;
	a = ++b + c--;		//相当于顺序执行 b=b+1,a=b+c,c=c-1
	printf("%d,%d,%d\n", a, b, c);
	a = b-- - c;		//相当于顺序执行 a=b-c,b=b-1
	printf("%d,%d,%d\n", a, b, c);
	a = -b++ + c;		//相当于执行a=-b+c,b=b+1
	printf("%d,%d,%d\n", a, b, c);
        a-=a-5;
        printf("%d\n",a);
	return 0;
}
/* 给一个正整数, 
* 1,求出这是几位数 
* 2,逆序输出它的每一位数字 
* 3,!!通过逆序输出的每一位数字,重新合成这个正整形数据(不允许用reverse,atoi等函数 以及 数组 )*/ 
#include <stdio.h> 
#include <math.h> 

int main(void) 
{ 
int a, i, temp, count = 1;	//count记录位数 
printf("input a int number : "); 
scanf("%d", &a);	//a为输入的数字 
temp = a; 

while (a / 10 != 0) { 
++count; 
a = a / 10; 
} 
printf("这个数字有%d位数\n", count); 

a = temp; 
temp = 0; 
for (i = 0; i < count; ++i, a = a / 10) { 
printf("%d ", a % 10); 
temp += a % 10 * pow(10, i);	//这里我借助了pow函数,有没有更简洁,不借助其他函数的办法呢? 
} 
printf("\n"); 

printf("这个数字是%d\n", temp); 
return 0; 
} 
minute + 1 = hour;
等号左边的表达式要求表示一个存储位置而不是一个值,这是等号运算符和+ - * /运算符的又一个
显著不同。有的表达式既可以表示一个存储位置也可以表示一个值,而有的表达式只能表示值,不
能表示存储位置,例如minute + 1这个表达式就不能表示存储位置,放在等号左边是语义错误。表
达式所表示的存储位置称为左值(lvalue)(允许放在等号左边),而以前我们所说的表达式的值
也称为右值(rvalue)(只能放在等号右边)。上面的话换一种说法就是:有的表达式既可以做左
值也可以做右值,而有的表达式只能做右值。目前我们学过的表达式中只有变量可以做左值,可以
做左值的表达式还有几种,以后会讲到

如果定义三个变量int a, b, c;,表达式a = b = c是合法的,先求b =
c的值,再把这个值赋给a,而表达式(a = b) = c是不合法的,先求(a = b) 的值没问题,但(a =
b) 这个表达式不能再做左值了,因此放在= c的等号左边是错的。

    在C语言中整数除法取的既不是Floor也不是Ceiling,无论操作数是正是负总是把小数部分截掉,在
数轴上向零的方向取整(Truncate toward Zero)


局部变量可以用类型相符的任意表达式来初始化,而全局变量只能用常量表达式
(Constant Expression)初始化。
如果全局变量在定义时不初始化则初始值是0,如果局部变量在定义时不初始化则初始值是不确定的。所以,局部变量在使用之前一定要先赋值,如果基于一个不确定的值做后续计算肯定会引入Bug。

(a/b)*b+a%b的值总是等于a

A<B<C,不同于数学中的 a<b and b<c,而是等同于 a<b,为true或false,即1,0 ,然后判断1或0是否<c

以下哪一个if判断条件是多余的可以去掉?这里所谓的“多余”是指,某种情况下如果本来应该打印Test OK! ,去掉这个多余条件后仍然打印Test OK! ,如果本来应该打印Test failed!,去掉这个多余条件后仍然打印Test failed!。
if (x<3 && y>3)
    printf("Test OK!\n");
    else if (x>=3 && y>=3)
    printf("Test OK!\n");
    else if (z>3 && x>=3)
    printf("Test OK!\n");
    else if (z<=3 && y>=3)
    printf("Test OK!\n");
    else
    printf("Test failed!\n");
这个文件用typedef工具创建了新的类型名字。
比如:uint32_t作为一个具有某种特征的标准类型的同义词或别名。在某系统中这个标准类型可能是unsigned int,另一个系统可能是unsigned long.编译器会提供所在系统相一致的头文件。这个新的名称叫做“确切长度类型”。

使用“确切长度类型”的一个潜在问题是某些系统可能不支持一些选择,例如int8_t类型。C99标准定义了第二组名字结合。这些名字保证所表示的类型至少大于指定长度的最小类型。被称为“最小长度类型”。例如 int_least8_t,他在某些机器的实现也许是16位整数。

“最快最小长度类型” int_fast8_t。
“最大可能整数类型” intmax_t uintmax_t

C99为表示浮点常量新添加了一种十六进制格式。最后是2的指数,而不是10
0xa.1fp10
a是10, 1f为十六进制小数,转2进制为1/16+15/256.  p10表示2的十次方。结果为 (10+1/16+15/256)*2^10
#include	<stdio.h>
						/* 参数传递机制 */
int main(void)
{
	float n1 = 3.0;
	double n2 = 3.0;
	long n3 = 2000000000;
	long n4 = 1234567890;
	long n3_2 = 78888888;

	printf("%ld %ld %ld %ld %ld\n", n1, n2, n3, n4, n3_2);
/* 该调用告诉计算机把变量n1...n4的值传给计算机。计算机把他们放知道被称为堆栈(stack)的一块内存区域中来实现。计算机根据变量的类型而非转换说明符把这些值放到堆栈中。所以,n1 在堆栈中占用8B(float被转换为double),n2 8B,n3/n4 4B。
 * 然后控制转移到printf()函数。它在读取时,根据转换说明符号读取。%ld说明pf()读取4个字节。所以返回结果如下
 * 0 1074266112 0 1074266112
 * 如果我们再声明一个long int数值,读取的应该就是n3的值了。
 */
	return 0;
}
#include	<stdio.h>

void show_array(double ar[], int n)
{
	int i;

	for (i = 0; i < n; i++)
		printf("%8.3f", ar[i]);
	putchar('\n');
}

int main(void)
{
	double rates[5] = { 88.99, 100.12, 59.45, 183.11, 340.5 };
	const double *pd = rates;	/* 指向常量的指针不能用于修改数值,
					   这一行把pd声明为指向 const double的指针 */
	double *const pc = rates;	/* 指针不会指向别处,不可更改 */
//不允许*pd = 29.89;
//      pd[2] = 222.22;

	rates[0] = 99.99;
	pd++;			/* 让pd指向rates[1],这是允许的 */

	const double locked[5] = { 88.99, 100.12, 59.45, 183.11, 340.5 };
	double *pnc;
//只有非常量的地址才可以赋给普通指针   
//非法:   pnc = locked;
//将常量数组作为非常量数组参数会警告或出错
	show_array(locked, 5);
  
	return 0;
}
#include	<stdio.h>

int main(void)
{
	int a[5] = { 5, 2, 3, 1, 4 };
	int *p1;
	const int *p2;
	const int **pp2;

	p2 = a;

	p1 = p2;		/* 非法,把const指针赋值给非const指针 */
	p2 = p1;		/* 合法,把非const指针赋值给const指针 */

	pp2 = &p1;		/* 非法,把非const指针赋值给const指针 */

	return 0;
}
括号成员第一;        //括号运算符[]() 成员运算符.  ->
全体单目第二;        //所有的单目运算符比如++ -- +(正) -(负) 指针运算*&
乘除余三,加减四;  //这个"余"是指取余运算即%
移位五,关系六;    //移位运算符:<< >> ,关系:> < >= <= 等
等于(与)不等排第七;    //即== !=
位与异或和位或;    //这几个都是位运算: 位与(&)异或(^)位或(|)    
"三分天下"八九十;  
逻辑或跟与;            //逻辑运算符| 和 &&
十二和十一;            //注意顺序:优先级(||)  底于 优先级(&&) 
条件高于赋值,      //三目运算符优先级排到 13 位只比赋值运算符和","高//需要注意的是赋值运算符很多!
逗号运算级最低!  //逗号运算符优先级最低
/*-----------------------------------------------------------------------------
 *  typedef建立的一系列相关类型
 *-----------------------------------------------------------------------------*/

typedef int arr5[5];
typedef arr5 *p_arr5;
typedef p_arr5 arrp10[10];

arr5 togs;			/* togs是具有5个元素的int数组 */
p_arr5 p2;			/* p2是一个指针,指向具有5个元素的int数组 */
arrp10 ap;			/* ap是具有10个元素的指针数组,每个指针指向具有5个元素的int数组 */
Initializer中的数据依次赋给结构体的各成员。如果Initializer中的数据比结构体的成员多,编译器会报错,但如果只是末尾多个逗号则不算错。如果Initializer中的数据比结构体的成员少,未指定的成员将用0来初始化,就像未初始化的全局变量一样。
z1必须是局部变量才能用另一个变量x的值来初始化它的成员,如果是全局变量就只能用常量表达式来初始化。这也是C99的新特性,C89只允许在{}中使用常量表达式来初始化,无论是初始化全局变量还是局部变量。
a,如果两边都是有符号数或无符号数,那么较低Rank的类型转换成较高Rank的类型

b,如果一边是符号数另一边是有符号数。
如果无符号数Rank不低于有符号数的Rank,则把有符号数转换为另一边的无符号类型。

如果无符号数Rank低于有符号数的Rank。此时分两种情况。
(1),如果这个有符号数类型能够覆盖这个无符号数类型的取值范围,则把无符号数转成另一边的有符号类型。
(2),否则把两边都转换成有符号数Rank对应的无符号类型。