一生一芯--c语言学习(linux c 编程一站式学习)

习题1-8,11-12稍微鸽下,还在感悟中.21-24

第一章程序的基本概念

第二章-常量,变量和表达式

1、总结前面介绍的转义序列的规律,想想在printf的格式化字符串中怎么表示一个%字符?写个小程序试验一下。

void test01()
{
	printf("%%\n");
}

2、假设变量x和n是两个正整数,我们知道x/n这个表达式的结果是取Floor,例如x是17,n是4,则结果是4。如果希望结果取Ceiling应该怎么写表达式呢?例如x是17,n是4,则结果是5,而x是16,n是4,则结果是4。

void test02()
{
	int a, b;
	scanf_s("%d %d", &a,&b);
	printf("%d", (a-1)/b+1);
}

第三章-简单函数

1、定义一个函数increment,它的作用是将传进来的参数加1,然后在main函数中用increment函数来增加变量的值:

void increment(int *x)
{
	*x=*x + 1;
}

int main(int argc,char *argv[])
{
	int i = 1, j = 2;
	increment(&j);
	increment(&i);
	printf("%d %d", i, j);
	return 0;
}

2、函数的声明,定义,原型

main() {}, int bar(void) {}是函数定义
int foo();函数声明
void baz(int i, int);函数原型

第四章-分支语句

1、以下程序段编译能通过,执行也不出错,但是执行结果不正确(根据第 3 节 “程序的调试”的定义,这是一个语义错误),请分析一下哪里错了。还有,既然错了为什么编译能通过呢?

int x = -1;
if (x > 0);
    printf("x is positive.\n");

if判断后有个分号; 但是这不是语法错误,所以能够编译通过。

void test04()
{
	int x = -1;
	if (x > 0)
		printf("x is positive");
	else
		printf("x is negetive");
}

2、写两个表达式,分别取整型变量x的个位和十位。

void test05()
{
	printf("请输入一个整数:\n");
	int x = 0;
	scanf_s("%d", &x);
	printf("他的个位是:%d\n", x % 10);
	printf("他的十位是:%d\n", (x / 10) % 10);
}

3、写一个函数,参数是整型变量x,功能是打印x的个位和十位

void print_digits(int x) 
{
	int units = x % 10;
	int tens = (x / 10) % 10;
	printf("个位:%d,十位:%d\n", units, tens);
}

p50-p51 1-3,5页 easy
以下哪一个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");

正确的:

void test06_1()
{
	int x=0, y=0,z=0;
	if(x < 3 && y>3)
		printf("ok");
else if (x >= 3 && y >= 3)//多余
printf("ok");
else if (z > 3 && y > +3)
printf("ok");
else if (z <= 3 && y >= 3)
printf("ok");
else
printf("no");
}

第五章-深入理解函数

1、编写一个布尔函数int is_leap_year(int year),判断参数year是不是闰年。如果某年份能被4整除,但不能被100整除,那么这一年就是闰年,此外,能被400整除的年份也是闰年。

int is_leap_year(int year) {
	if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
		return 1; // 是闰年
	}
	else {
		return 0; // 不是闰年
	}
}
int main() {
	int year;
	printf("请输入一个年份:");
	scanf_s("%d", &year);

	if (is_leap_year(year)) {
		printf("%d 是闰年\n", year);
	}
	else {
		printf("%d 不是闰年\n", year);
	}

	return 0;
}

2、编写一个函数double myround(double x),输入一个小数,将它四舍五入。例如myround(-3.51)的值是-4.0,myround(4.49)的值是4.0。可以调用math.h中的库函数ceil和floor实现这个函数。

double myround(double x)
{
	double a, b;
	if (x >= 0)
	{
		return ceil(x - 0.5);
	}
	else if (x == 0)
		return 0;
	else
		return floor(x + 0.5);

}
int main()
{
	double data,pro_data;
	printf("请输入一个数:");
	scanf_s("%lf", &data);
	pro_data = myround(data);
	printf("data进行四舍五入后结果为%lf", pro_data);
}

3、编写递归函数求两个正整数a和b的最大公约数(GCD,Greatest Common Divisor),使用Euclid算法:
如果a除以b能整除,则最大公约数是b。
否则,最大公约数等于b和a%b的最大公约数。 Euclid算法是很容易证明的,请读者自己证明一下为什么这么算就能算出最大公约数。

int gcd_euclid(int a, int b)
{
	a = (a < 0) ? -a : a;
	b = (b < 0) ? -b : b;
	if (a % b == 0)
		return b;
	else
	{
		return gcd_euclid(b, a % b);
	}

}

int main()
{
	int x, y;
	printf("请输入两个数:");
	scanf_s("%d %d", &x, &y);
	printf("最大公约数是:%d",gcd_euclid(x, y));
}

4、编写递归函数求Fibonacci数列的第n项,这个数列是这样定义的: fib(0)=1 fib(1)=1 fib(n)=fib(n-1)+fib(n-2) 这个递归函数做两次递归调用,会形成树状的调用关系,需要画图解释。

int fib(int n)
{ 
	int result;
	if (n == 1 || n == 0)
		return 1;
	else
	{
		result = fib(n - 2) + fib(n - 1);
		return result;
	}
		
}
int main()
{
	int n;
	printf("请输入1个数:");
	scanf_s("%d",&n);
	printf("他的fib是:%d", fib(n));
}

第六章-循环语句

1、使用while实现:

int gcd_euclid_while(int a, int b) {
	// 步骤1:先处理负数,取绝对值
	a = (a < 0) ? -a : a;
	b = (b < 0) ? -b : b;

	while (b != 0 && a % b != 0) {
		int temp = b;       // 保存当前b的值
		b = a % b;          // 更新b为a除以b的余数
		a = temp;           // 更新a为原来的b
	}
	return (b == 0) ? a : b;
}
int fib_while(int n) {
	if (n == 0 || n == 1) {
		return 1;
	}

	int a = 1;  
	int b = 1;  
	int result = 0;
	int i = 2;  // 从第2项开始计算(n>=2)

	while (i <= n) {
		result = a + b;  // 当前项 = 前两项之和
		a = b;           // 更新前一项
		b = result;      // 更新当前项为下一次的前一项
		i++;
	}

	return result;
}

2、编写程序数一下1到100的所有整数中出现多少次数字9。在写程序之前先把这些问题考虑清楚:

  • 这个问题中的循环变量是什么?
  • 这个问题中的累加器是什么?用加法还是用乘法累积?
  • 在第 2 节 “if/else语句”的习题1写过取一个整数的个位和十位的表达式,这两个表达式怎样用到程序中?
void test09()
{
	int n = 100;
	int i = 0;
	while (n>0)
	{
		
		if ((n % 10) == 9 || ((n / 10) % 10) == 9)
		{
			i++;
			printf("包含数字9:%d\n", n);
		}
		
		n--;
		
	}
	printf("包含数字9的数有%d个",i);
}

3、求素数这个程序只是为了说明break和continue的用法才这么写的,其实完全可以不用break和continue,请读者修改一下循环的结构,去掉break和continue而保持功能不变

int is_prime(int n) {
	if (n <= 1) {
		return 0;
	}
	if (n == 2) {
		return 1;
	}
	if (n % 2 == 0) {
		return 0;
	}

	for (int i = 3; i * i <= n; i += 2) {
		if (n % i == 0) {  
			return 0;
		}
	}
	return 1;
}

int main5()
{
	int i;
	for (i = 1; i<= 100;i++)
	{
		if (is_prime(i))
			printf("%d不是素数\n", i);
		else 
			printf("%d是素数\n", i);
	}
	return 0;

}

4、上面打印的小九九有一半数据是重复的,因为89和98的结果一样。请修改程序打印这样的小九九:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49
8 16 24 32 40 48 56 64
9 18 27 36 45 54 63 72 81

void test10()
{
	int n = 9;
	int i, j;
	for (i = 1;i <= n;i++)
	{
		for (j = 1;j <= i;j++)
		{
			printf("%d ", i * j);
		}
		printf("\n");
	}
}

5、编写函数diamond打印一个菱形。如果调用diamond(3, '*')则打印:(看书p74)

void diamond(int n, char ch)
{
	if (n % 2 == 0)
	{
		printf("error");
		return;
	}
	//上半部分
	for (int i = 0; i < n / 2 + 1; i++)
	{
		for(int j =n/2-i;j>0;j--)
		{
			printf(" ");
		}
		for (int k = 0;k<2*i+1;k++)
		{
			printf("%c",ch);
		}
		printf("\n");
	}
	//上半部分
	for(int i = 0; i < n / 2 ; i++)
	{
		for (int j=0;j<i+1;j++)
		{
			printf(" ");
		}
		for (int k = 2*(n/2-i)-1;k>0;k--){
		
			printf("%c", ch);
		}
		printf("\n");
	}
		
}

6、以下代码编译没有问题, 但运行结果却和预期不符合, 不能打印出other number, 请分析原因.

#include <stdio.h>
int main(void){
    int n = 3;
    switch(n) {
        case 1:
            printf("1\n");
            break;
        case 2:
            printf("2\n");
            break;
        default:
            printf("other number\n");
    }
    return 0;
}

正确的:

void test12()
{
	int n = 3;
	switch (n)
	{
	case 1:
		printf("1\n");
		break;
	case 2:
		printf("2\n");
		break; 
	default:
		printf("other number\n");

	}
}

7、这题我使用visual studio能正常打印出other number

第七章-结构体

1、在本节的基础上实现一个打印复数的函数,打印的格式是x+yi,如果实部或虚部为0则省略,例如:1.0、-2.0i、-1.0+2.0i、1.0-2.0i。最后编写一个main函数测试本节的所有代码。想一想这个打印函数应该属于上图中的哪一层?

#include <stdio.h>
#include <math.h>
//p85页习题
struct complex_num {
	double x, y;
};
double real(struct complex_num z)
{
	return z.x;
}
double img(struct complex_num z)
{
	return z.y;
}
void printf_complex_num(struct complex_num z)
{
	if (real(z) == 0 && img(z) == 0)
		printf("0\n");
	else if (real(z) == 0)
		printf("%fi\n", img(z));
	else if (img(z) == 0)
		printf("%f\n", real(z));
	else
		printf("%f+%fi\n", real(z), img(z));
}

2、实现一个用分子分母的格式来表示有理数的结构体rational以及相关的函数,rational结构体之间可以做加减乘除运算,运算的结果仍然是rational 注意要约分为最简分数,例如1/8和-1/8相减的打印结果应该是1/4而不是2/8,可以利用第 3 节 “递归”练习题中的Euclid算法来约分。在动手编程之前先思考一下这个问题实现了什么样的数据抽象,抽象层应该由哪些函数组成。

struct rational {
	int x, y;
};
//注意到例子,make_ratonal返回值是一个结构体
struct rational make_rational(int numerator, int denominator)
{
	struct rational a;
	a.x = numerator;
	a.y = denominator;
	return a;
}
//一个细节,这里分数加法需要取最小公倍数使用函数章节例题gcd
int gcd_euclid(int a, int b)
{
	a = (a < 0) ? -a : a;
	b = (b < 0) ? -b : b;
	if (a % b == 0)
		return b;
	else
	{
		return gcd_euclid(b, a % b);
	}

}
void printf_rational(struct rational num)
{
	printf("%d/%d\n", num.x, num.y);
}
struct rational add_rational(struct rational a, struct rational b)
{
	struct rational result;
	int max, gcm;
	//百度下,最大公倍数=axb/gcd_eucild(a,b)
	max = gcd_euclid(a.x, b.y);
	gcm = (a.x * b.y) / max;
	result.y = gcm;
	result.x = (a.x * gcm / a.y) + (b.x * gcm / b.y);
	return result;
}
struct rational sub_rational(struct rational a, struct rational b)
{
	struct rational result;
	int max, gcm;
	//百度下,最大公倍数=axb/gcd_eucild(a,b)
	max = gcd_euclid(a.x, b.y);
	gcm = (a.x * b.y) / max;
	result.y = gcm;
	result.x = (a.x * gcm / a.y) - (b.x * gcm / b.y);
	return result;
}
struct rational mul_rational(struct rational a, struct rational b)
{
	struct rational result;
	result.x = a.x * b.x;
	result.y = a.y * b.y;
	return result;
}
struct rational div_rational(struct rational a, struct rational b)
{
	struct rational result;
	result.x = a.x * b.y;
	result.y = a.y * b.x;
	return result;
}
void main()
{
	struct complex_num z1 = { 1,1 };
	printf_complex_num(z1);
	struct complex_num z2 = { 0,1 };
	printf_complex_num(z2);
	struct complex_num z3 = { 1,0 };
	printf_complex_num(z3);
	struct complex_num z4 = { 0,0 };
	printf_complex_num(z4);

	struct rational a = make_rational(1, 8);
	struct rational b = make_rational(-1, 8);
	printf_rational(add_rational(a, b));//0/8
	printf_rational(sub_rational(a, b));//2/8
	printf_rational(div_rational(a, b));//8/-8
	printf_rational(mul_rational(a, b));//-1/64
	return 0;
	
}

3、本节只给出了make_from_real_img和make_from_mag_ang函数的实现,请读者自己实现real_part、img_part、magnitude、angle这些函数。

enum coordinate_type { RECTANGULAR,POLAR};
struct  complex_struct1
{
	enum coordinate_type t;
	double a, b;
};

double real_part(struct complex_struct1 z) {
	if (z.t == RECTANGULAR)
		return z.a;
	else
		return z.a * cos(z.b);
}
double imag_part(struct complex_struct1 z) {
	if (z.t == RECTANGULAR)
		return z.b;
	else
		return z.a * sin(z.b);
}
double magnitude(struct complex_struct1 z) {
	if (z.t == RECTANGULAR)
		return sqrt(z.a * z.a + z.b * z.b);
	else
		return z.a;
}
double angle(struct complex_struct1 z) {
	if (z.t == RECTANGULAR) {
		double PI = acos(-1.0);
		if (z.a > 0)
			return atan(z.b / z.a);
		else
			return atan(z.b / z.a) + PI;
	}
	else
		return z.b;
}
int main(void)
{
	int RECTANGULAR;
	printf("%d %d\n", RECTANGULAR, POLAR);
	return 0;
}

4、编译运行下面这段程序:

#include <stdio.h>
enum coordinate_type { RECTANGULAR = 1, POLAR };
int main(void)
{
    int RECTANGULAR;
    printf("%d %d\n", RECTANGULAR, POLAR);
    return 0;
}

结果是什么?并解释一下为什么是这样的结果。
解答:结果是一个随机值,polAr是2,但是int rectangular没有别初始化。

第八章-数组

1、编写一个程序,定义两个类型和长度都相同的数组,将其中一个数组的所有元素拷贝给另一个。既然数组不能直接赋值,想想应该怎么实现。

#include<stdio.h>
#include<stdlib.h>
#define N 20
int a[N];//定义一个全局变量
//习题1在 C 语言中,字符串是以空字符 (\0) 结尾的。当循环执行时,b[i] 会取源字符串 b 中索引为 i 的字符。在 C 语言的布尔表达式中,任何非零值都被视为真,零值(\0) 被视为假
void copy(char *a, char *b) {
    int i;
    for (i = 0; b[i]; ++i)
        a[i] = b[i];
}

2、用rand函数生成10~20之间的随机整数,表达式应该怎么写?
num=rand()%11+10
3、补完本节直方图程序的main函数,以可视化的形式打印直方图。 注:其他随机数程序写一块了,mainx去掉对应的x就可以用

void gen_random(int upper_bound)
{
    int i;
    for (i = 0;i < N;i++)
    {
        a[i] = rand() % upper_bound;
    }
}

void print_random()
{
    int i;
    for (i = 0;i < N;i++)
        printf("%d ", a[i]);
    printf("\n");
}


int main1(void)
{
    gen_random(1000);
    print_random();
    return 0;
}

int howmany(int value)
{
    int count = 0, i;
    for (i = 0;i < N;i++)
    {
        if (a[i] == value)
            ++count;
    }
    return count;
}

int main2(void)
{
    int i;
    gen_random(10);
    printf("value\thow many\n");
    for (i = 0;i < 10;i++)
    {
        printf("%d\t%d\n", i, howmany(i));
    }
    return 0;
}
int main3(void)
{
    int i, histogram[10] = { 0 };
    gen_random(10);
    for (i = 0;i < N;i++)
        histogram[a[i]]++;
    return 0;

}

void printf0_9()
{
    int i;
    for(i=0;i<10;i++)
    printf("%d ",i);

    printf("\n");
}
void num_count(int *num)
{
    int i, histogram[10] = { 0 };
    gen_random(10);
    for (i = 0;i < N;i++)
        histogram[a[i]]++;
    for (i = 0;i < N;i++)
        num[i]=histogram[i];

}
int main4(void)
{ 
    printf0_9();
    int i;
    int histogram[10];
    num_count(histogram);
    printf("实际个数统计如下:\n");
    for (i = 0;i < 10;i++)
        printf("%d ", histogram[i]);

    int max = histogram[0];
    for (i = 0;i < 9;i++)
    {
        if (histogram[i] >= max)
            max = histogram[i];
   }
    printf("出现次数最多是:%d\n",max);
    int j;

    for (i = 0;i <max;i++)
    {
        for (j = 0;j < 10;j++)
        {
            if (histogram[j] > i)
                printf("* ");
            else
                printf("  ");
        }
        printf("\n");
    }
}

4、定义一个数组,编程打印它的全排列

//p97 习题2
#define N 3
int a[N] = { 1, 2, 3 }; // 原始数组
int result[N];         // 存储当前排列的数组
int used[N] = { 0 };     // 标记数组:used[i] = 1 表示 a[i] 已经被使用

// 函数声明
void permute(int k);

int main() {
    printf("--- 数组 {1, 2, 3} 的全排列 ---\n");
    permute(0); // 从第0个位置开始生成排列
    return 0;
}

void permute(int k)
{
    if (k == N) {
        for (int i = 0; i < N; i++) {
            printf("%d ", result[i]);
        }
        printf("\n");
        return;//第一轮循环时候,permute(3)是permute(2)调用因此return是回到permute(2)
    }
    else
        for (int i = 0; i < N; i++) 
    {
            if (used[i] == 0) {
                result[k] = a[i];
                used[i] = 1;
                //递归调用,去填充下一个位置 k+1
                permute(k + 1);
                used[i] = 0;

            }
                
    }
}

5、p103思考题,石头剪刀布

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(void)
{
	char gesture[3][10] = { "scissor","stone","cloth" };
	int man, computer, result, ret;

	srand(time(NULL));//随机数相关,time时间戳srand重置随机数种子
	while (1)
	{
		computer = rand() % 3;
		printf("0-scissor,1-stone,2-cloth \n");
		ret = scanf("%d", &man);//scanf实际上也是一个函数,合法时候返回1
		if (ret != 1 || man < 0 || man>2)
		{
			printf("invalid input\n");
			return 1;
		}
		printf("you: %s\tcomputer:%s\n",gesture[man], gesture[computer]);
		result = (man - computer + 4) % 3 - 1;//数值带入进去展开就知道了
		if (result > 0)
		{
			printf("you win\n");
		}
		else if (result == 0)
		{
			printf("Draw\n");
		}
		else
			printf("you lose\n");
	}
	return 0;
}

第十一十二章(难)

插入排序

这个图很形象:
https://www.runoob.com/wp-content/uploads/2019/03/insertionSort.gif
算法过程(自己的理解):
(1)取数 定义一个for循环,j自加取数
(2)比较 将取出的数和j前面的数组的数进行比较
(3)插入 找到合适位置进行插入
(4) 循环 下一轮循环
习题:p341页
1、定义一个二维数组,例如int a[][5]={23,43,4,5,7,45,42,12,11,66,55,47,33,89,1};,编写程序进行排序(从小到大)

#思路就是展开成为一维数组处理
#include <stdio.h>
int main() {
    int a[][3] = {  // 假设3列
        23, 43, 4, 5, 7, 45,
        42, 12, 11, 66, 55, 47,
        33, 89, 1
    };

    int rows = sizeof(a) / sizeof(a[0]);  // 行数
    int cols = sizeof(a[0]) / sizeof(a[0][0]);  // 列数
    int total = rows*cols;  // 总元素个数
    printf("%d\n",total);
    int flat[15];//这里的数组,我的编译器要求数组大小必须是常量

    int index = 0;
    int key,i,j;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            flat[index++] = a[i][j];
        }
    }

    for (i = 1;i < total;i++)
    {
        key = flat[i];
        j = i - 1;
        while (j >= 0 && key<=flat[j])
        {
            flat[j + 1] = flat[j];
                j--;
        }
        flat[j + 1] = key;
    }


    index = 0;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            a[i][j] = flat[index++];
        }
    }

    printf("排序后的二维数组:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%3d ", a[i][j]);
        }
        printf("\n");
    }

    return 0;
}

选择排序

https://www.runoob.com/wp-content/uploads/2019/03/selectionSort.gif
上面的使用选择排序实现

#include <stdio.h>

int main1() {
    int a[][3] = {  // 假设3列
        23, 43, 4, 5, 7, 45,
        42, 12, 11, 66, 55, 47,
        33, 89, 1
    };

    int rows = sizeof(a) / sizeof(a[0]);  // 行数
    int cols = sizeof(a[0]) / sizeof(a[0][0]);  // 列数
    int total = rows*cols;  // 总元素个数
    printf("%d\n",total);
    int flat[15];

    int index = 0;
    int key,i,j;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            flat[index++] = a[i][j];
        }
    }

    for (i = 1;i < total;i++)
    {
        key = flat[i];
        j = i - 1;
        while (j >= 0 && key<=flat[j])
        {
            flat[j + 1] = flat[j];
                j--;
        }
        flat[j + 1] = key;
    }


    index = 0;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            a[i][j] = flat[index++];
        }
    }

    printf("排序后的二维数组:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%3d ", a[i][j]);
        }
        printf("\n");
    }

    return 0;
}

int main() {
    int a[][3] = {  // 假设3列
        23, 43, 4, 5, 7, 45,
        42, 12, 11, 66, 55, 47,
        33, 89, 1
    };

    int rows = sizeof(a) / sizeof(a[0]);  // 行数
    int cols = sizeof(a[0]) / sizeof(a[0][0]);  // 列数
    int total = rows * cols;  // 总元素个数

    // 创建一维数组
    int flat[15];

    // 将二维数组展平
    int index = 0;
    int min, i, j,tmp;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            flat[index++] = a[i][j];
        }
    }

    printf("展平后的一维数组(排序前): ");
    for (int i = 0; i < total; i++) {
        printf("%d ", flat[i]);
    }
    printf("\n\n");
    for (j = 0;j < total;j++)
    {
        min = flat[j];
       
        for (i = j+1;i<total;i++)
        {
            if (flat[i] < min)
            {
                min = flat[i];  
                flat[i] = flat[j];
                flat[j] = min;
            }
        }
    }
    printf("\n排序后的一维数组: ");
    for (int i = 0; i < total; i++) {
        printf("%d ", flat[i]);
    }
    printf("\n\n");

    // 将排序后的一维数组放回二维数组
    index = 0;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            a[i][j] = flat[index++];
        }
    }

    printf("排序后的二维数组:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%3d ", a[i][j]);
        }
        printf("\n");
    }

    return 0;
}

归并排序

void merge(int start, int mid, int end) {
    int n1 = mid - start + 1;
    int n2 = end - mid;

    // 动态分配内存
    int *left = (int *)malloc(n1 * sizeof(int));
    int *right = (int *)malloc(n2 * sizeof(int));

    if (left == NULL || right == NULL) {
        printf("内存分配失败!\n");
        return;
    }

    int i, j, k;

    // 复制数据
    for (i = 0; i < n1; i++)
        left[i] = a[start + i];
    for (j = 0; j < n2; j++)
        right[j] = a[mid + 1 + j];

    i = j = 0;
    k = start;

    // 合并
    while (i < n1 && j < n2)
        if (left[i] < right[j])
            a[k++] = left[i++];
        else
            a[k++] = right[j++];

    while (i < n1)
        a[k++] = left[i++];
    while (j < n2)
        a[k++] = right[j++];

    // 释放内存
    free(left);
    free(right);
}
void sort(int start, int end)
{
    int mid;
    if (start < end)
    {
        mid = (start + end) / 2;
        printf("sort(%d-%d,%d-%d) %d %d %d %d %d %d %d %d\n", start, mid, mid + 1, end, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
        sort(start, mid);
        sort(mid + 1, end);
        merge(start, mid, end);
        printf("sort(%d-%d,%d-%d)to %d %d %d %d %d %d %d %d\n", start, mid, mid + 1, end, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
    }
}

int main(void)
{
    sort(0, LEN - 1);
    return 0;
}

深度优先算法

广度优先算法

第22章-指针

1、思考一下,为什么要用typedef定义类型名而不用#define定义类型名?比如:

typedef int *pint_t
#define pint_t int *

有何区别

网上这个解答很好:
typedef是类型别名,define是文本替换
//typedef版本
pint_t a, b; 
// 等价于:int *a, *b; (a和b都是int*类型,符合预期)
// #define版本
pint_t a, b; 
// 预处理后替换为:int *a, b; 
// 实际效果:a是int*,b是int(仅第一个变量是指针)

2-3
对照本节的描述,像图 23.1 “指针的基本概念”那样画图理解函数的调用和返回过程。在下一章我们会看到更复杂的参数和返回值形式,在初学阶段对每个程序都要画图理解它的运行过程,只要基本概念清晰,无论多复杂的形式都应该能正确分析。

现在回头看第 3 节 “形参和实参”的习题1,那个程序应该怎么改?
改成用地址传递了
4、

posted @ 2025-12-12 11:07  与非或非门  阅读(11)  评论(0)    收藏  举报