asuerhao's Blog

如果有什么做的不到的地方请尽管留言, 我会改进的 : )

汉诺塔的递归实现

    汉诺塔问题简介: http://zh.wikipedia.org/wiki/%E6%B1%89%E8%AF%BA%E5%A1%94

    其递归实现的函数原型为: 'void hanoi(int n, char a, char b, char c);'.  其中字符变量'a', 'b', 'c'分别表示从杆子a, 杆子b, 杆子c, 整数变量'n'表示汉诺塔问题的阶数(即杆子a上有n个待移动到杆子c的圆盘, 杆子b作为临时杆子).

    其递归实现的步骤为:
  1. 如果n==1, 则直接将唯一的圆盘从杆子a移动到杆子c, 问题解决.
  2. 否则, 将杆子a上的(n-1)个圆盘移动到杆子b(通过递归实现),
       然后将杆子a上剩余的最大的圆盘移动到杆子c,
       最后将杆子b上的(n-1)个圆盘移动到杆子c(通过递归实现), 问题解决.

其递归实现的C代码为:

#include<stdio.h>
void hanoi(int, char, char, char);
int main(void)
{
	int n=3;
	printf("输入数字n:\n");
	scanf("%d", &n);
	hanoi(n, 'A', 'B', 'C');
	return 0;
}
void hanoi(int n, char a, char b, char c)
{
	if(n==1) {
		printf("%c->%c\n", a, c);
	} else {
		hanoi(n-1, a, c, b);
		printf("%c->%c\n", a, c);
		hanoi(n-1, b, a, c);
	}

}

  之前在笔试中遇到的, 记录一下.

C 数据类型转换

    看一下段代码, 分析for循环的循环体会执行多少次:

#include<stdio.h>
int main(void)
{
	int i;
	for(i=-1; i < sizeof(int); i++) {
		printf("%d, ", i);
	}
	return 0;
}

    实验表明, 在不同的编译器下, 这个循环的实现也不一样:

    1. 在gcc下, 由于'sizeof(int)'的返回值是'unsigned long int'类型的, 但'i'的类型是'signed int'类型的, 二者在做比较时要将i从'signed int'转换成'unsigned long int', 但由于i原来是有符号的'-1', 转换后变为无符号的'0xffffffff', 当然比'sizeof(int)'大, 结果for循环体一次也没有执行.

    2. 在Turbo C下, 由于'sizeof(int)'的返回值是'signed int'类型的(注意: 这不符合C标准的规定), 所以与'i'比较是没有类型转换, for循环体会执行5次.

    严重注意: 有些东西了解就行, 以便在出现问题时知道如何解决, 但尽量不要在自己的代码中尝试那些东西.

C语言 char型也是分有符号数和无符号数的

  unsigned char型表示无符号数, 取值范围是 0~255.
  signed char型表示无符号数, 取值范围是 -128~127.

  在x86平台上, gcc规定不带'unsigned'或'signed'关键字的char是有符号的. 参见以下代码 :

#include<stdio.h>
int main(void)
{
	printf("(signed char)200: %d\n", (signed char)200);
	printf("(unsigned char)200: %d\n", (unsigned char)200);
	printf("(char)200: %d\n", (char)200);	// gcc定义char型是有符号的。
	return 0;
}


打印结果为:

(signed char)200: -56
(unsigned char)200: 200
(char)200: -56

  利用objdump工具对其进行反汇编, 观察向printf函数传递的第二个参数, 节选部分汇编代码:
    printf("(signed char)200: %d\n", (signed char)200);
 80483cd:    b8 e0 84 04 08                mov    $0x80484e0,%eax
 80483d2:    c7 44 24 04 c8 ff ff        movl   $0xffffffc8,0x4(%esp)
 80483d9:    ff
 80483da:    89 04 24                            mov    %eax,(%esp)
 80483dd:    e8 12 ff ff ff                    call   80482f4 <printf@plt>
    printf("(unsigned char)200: %d\n", (unsigned char)200);
 80483e2:    b8 f6 84 04 08                mov    $0x80484f6,%eax
 80483e7:    c7 44 24 04 c8 00 00    movl   $0xc8,0x4(%esp)
 80483ee:    00
 80483ef:    89 04 24                            mov    %eax,(%esp)
 80483f2:    e8 fd fe ff ff                     call   80482f4 <printf@plt>
    printf("(char)200: %d\n", (char)200);    // gcc定义char型是有符号的。
 80483f7:    b8 0e 85 04 08                mov    $0x804850e,%eax
 80483fc:    c7 44 24 04 c8 ff ff         movl   $0xffffffc8,0x4(%esp)
 8048403:    ff
 8048404:    89 04 24                            mov    %eax,(%esp)
 8048407:    e8 e8 fe ff ff                    call   80482f4 <printf@plt>

  还有一个问题需要注意, 从汇编代码可以看到, 实际上用了四个字节存储char类型的参量, 即: 像printf这种形参类型未知的函数, 调用函数时编译器会自动对相应的实参做Integer Promotion.

C 数组下标'[ ]'运算符

  C语言是通过数组下标来引用数组的, 我们这样定义一个有十个元素的整型数组:

int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  然后可以通过数组arr的下标对其元素进行引用:

a[0] = a[1]+a[2];

  实际上, 数组下标'[ ]'是一种运算符, 程序中用下标法引用数组元素的代码, 最终都被编译器自动转化为指针进行运算, 也就是说, 'a[i]'和'*(a+i)'在编译器看来, 是完全等价的.
  由此, 可以理解以下代码:

#include<stdio.h>
int main(void)
{
	struct hi {
		int a;
		int b;
	};
	struct hi test;
	test.a=1;
	test.b=2;
	printf("%d, %d\n", test.a, test.b);
	/* 真正写代码时, 请不要这样用: */
	printf("%d, %d\n", ((int*)(&test))[0], ((int*)(&test))[1]);
	return 0;
}

  打印结果为:
1, 2
1, 2

结构体和动态内存分配实现的单向列表结构

好像贴出这么多代码来现丑有些不合适,不过我是博主, 我说了算:

#include<stdio.h>
#include<stdlib.h>
struct one_way_list{
 	int data;
	struct one_way_list *next_node_pt;
}*head, *tail;  //定义结构体, 单向列表的一个结点.
int counter=0;  //计数器
//添加数据:
int app_data(int data) {
	if(counter==0){
		head=tail=(struct one_way_list *)malloc(sizeof(struct one_way_list));
		if(head==NULL){
			return(-1);
		}
		(*head).data=data;
	} else {
		(*tail).next_node_pt=(struct one_way_list *)malloc(sizeof(struct one_way_list));
		if((*tail).next_node_pt==NULL){
			return(-1);
		}
		tail=(*tail).next_node_pt;
		(*tail).data=data;
	}
	counter++;
	return(1);
}
//某数据是否存在:
int exists(int data) {
	if(counter==0){
		return(-1);
	} else {
		int i=0;
		struct one_way_list *pt=head;
		do{
			if((*pt).data==data) {
				return(i);
			}
			i++;
			pt=(*pt).next_node_pt;
		}while(pt != tail);
		return(-1);
	}
}
//查看计数器:
int count(void) {
	return(counter);
}
//查看列表头:
int head_data(void) {
	if(counter==0){
		return(-1);
	} else {
		return((*head).data);
	}
}
//查看列表尾:
int tail_data(void) {
	if(counter==0){
		return(-1);
	} else {
		return((*tail).data);
	}
}
//查看第i个数据:
int ith_data(int numth) {
	if(counter==0 || numth<0 || numth >= counter){
		return(-1);
	} else {
		int i=0;
		struct one_way_list tmp;
		tmp=*head;
		for(i=0; i!=numth; i++){
			tmp=*tmp.next_node_pt;
		}
		return(tmp.data);
	}
}
// 删除所有数据:
int delete_all(void) {
    struct one_way_list *pt=head;
    while(counter!=0) {
        pt=head;
        head=(*head).next_node_pt;
        free(pt);
        counter--;
    }
    return(1);
}
// 删除第i个数据:
int delete_ith(int numth) {
    if(counter==0 || numth<0 || numth>= counter) {
        return(-1);
    } else if(numth==0) {
        struct one_way_list *pt=head;
        head=(*head).next_node_pt;
        free(pt);
        return(1);
    } else {
        int i=0;
        struct one_way_list *pt_pr=head;
        struct one_way_list *pt=(*head).next_node_pt;
        for(i=1; i!=numth; i++) {
            pt_pr=(*pt_pr).next_node_pt;
            pt=(*pt).next_node_pt;
        }
        (*pt_pr).next_node_pt=(*pt).next_node_pt;
        free(pt);
        if(numth==counter) {
            tail=pt_pr;
        }
        return(1);
    }
}

//用于测试的主函数:
int main(void) {
	if(app_data(1) == -1){
		printf("Error1");
	}
	printf("counter: %d\n",counter);
	if(app_data(2) == -1){
		printf("Error2");
	}
	printf("counter: %d\n",counter);
	if(app_data(3) == -1){
		printf("Error3");
	}
	printf("counter: %d\n",counter);
	if(app_data(4) == -1){
		printf("Error4");
	}
	printf("counter: %d\n",counter);
	if(exists(1)>=0){
		printf("exits 1: %dth,\n", exists(1));
	} else {
		printf("1 not exits\n");
	}
	if(exists(9)>=0){
		printf("exits 9: %dth,\n", exists(9));
	} else {
		printf("9 not exits\n");
	}
	printf("count: %d\nhead: %d\ntail_data: %d\n", count(), head_data(), tail_data());
	printf("2th data:%d\n", ith_data(2));
    delete_all();
    printf("Just delete All.\n");
    if(app_data(7) == -1){
        printf("Error7");
    } else {
        printf("7 added\n");
    }
    printf("counter: %d\n",counter);
    if(app_data(6) == -1){
        printf("Error6");
    } else {
        printf("6 added\n");
    }
    printf("counter: %d\n",counter);
    if(app_data(5) == -1){
        printf("Error5");
    } else {
        printf("5 added\n");
    }
    printf("counter: %d\n",counter);
    if(delete_ith(1) == -1){
        printf("1th deleted error\n");
    } else {
        printf("1th deleted\n");
    }
    printf("1th: %d\n",ith_data(1));
    printf("head: %d\ntail: %d\n", head_data(), tail_data());
    return(0);
}