C经典88案例-第二部分

135 阅读13分钟

以下88案例打包下载地址

链接: www.keketec.club/posts/c065d…

案例ex23: 使用指针实现冒泡排序

1 题目

函数:bubble_order()

功能:使用指针实现冒泡排序

描述:实现C语言经典的冒泡排序

2 思路

冒泡排序的基本思路:

如果对 n 个数进行冒泡排序,则需要进行 n-1 躺比较,在第 1 趟比较中要进行 n-1 次两两比较,在第 j 趟比较中要进行 n-j 次两两比较

3 代码

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

/**
函数:bubble_order()
功能:使用指针实现冒泡排序
描述:实现C语言经典的冒泡排序
**/

void bubble_order(int *a, int n) {
	for (int i = 0; i < n-1; ++i) {
		for (int j = 0; j < n-1-i; ++j) {
			if (*(a+j) > *(a+j+1)) {
				*(a+j) = *(a+j) ^ *(a+j+1);
				*(a+j+1) = *(a+j) ^ *(a+j+1);
				*(a+j) = *(a+j) ^ *(a+j+1);
			}
		}
	}
}

int main(int argc, char const *argv[]) {
	int a[20], n;
	printf("请输入要排序元素的个数:\n");
	scanf("%d", &n);
	printf("请输入各个元素\n");
	for (int i = 0; i < n; ++i) {
		scanf("%d", a+i);
	}
	printf("排序前元素的内容为:\n");
	for (int j = 0; j < n; ++j) {
		printf("%d ", *(a+j));
	}
	bubble_order(a, n);
	printf("\n排序后元素的内容为:\n");
	for (int j = 0; j < n; ++j) {
		printf("%d ", *(a+j));
	}
	printf("\n");
	getchar();
}

示例结果:

$ gcc ex023.c -o demo
$ ./demo
请输入要排序元素的个数:
5
请输入各个元素
3
7
1
9
4
排序前元素的内容为:
3 7 1 9 4
排序后元素的内容为:
1 3 4 7 9

案例ex24: 输入月份号并输出英文月份名

1 题目

功能:输入月份号并输出英文月份名

描述:

使用指针数组创建一个含有月份英文名的字符串数组

并使用指向指针的指针指向这个字符串数组,实现输出数组中的指定字符串

2 思路

使用指针的指针实现对字符串数组中的字符串的输出

*month[] 属于指针数组,*month本身就是指针,数组中都是存放着指针。那么 month是指针数组的首地址,**p=month 指向数组中的每个元素

3 代码

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

/**
功能:输入月份号并输出英文月份名
描述:
使用指针数组创建一个含有月份英文名的字符串数组
并使用指向指针的指针指向这个字符串数组,实现输出数组中的指定字符串
**/

int main(int argc, char const *argv[]) {
	char *month[] = {
		"January",
		"February",
		"March",
		"April",
		"May",
		"June",
		"July",
		"August",
		"September",
		"October",
		"November",
		"December"
	};
	int m;
	char **p;   		// 指向指针的指针变量
	p = month;		// 数组首地址赋值给指针变量
	printf("输入一个月份号(阿拉伯数组):");
	scanf("%d", &m);
	printf("本月是:");
	printf("%s\n", *(p+m-1));
	getchar();
	return 0;
}

示例结果:

$ gcc ex024.c -o demo
$ ./demo
输入一个月份号(阿拉伯数组):3
本月是:March
$ ./demo
输入一个月份号(阿拉伯数组):9
本月是:September

案例ex25: 使用指针插入元素

1 题目

函数:insert()

功能:使用指针插入元素

描述:在有序(升序)的数组中插入一个数,使得插入的数组仍然有序

2 思路

  1. 参数传递,使用指针变量
  2. 插入数字,找到插入点,从数组的末端逐个向后移动,最后将要插入的数字放到插入点

3 代码

#include <stdio.h>
#include <stdlib.h>
#define N 10

/**
函数:insert()
功能:使用指针插入元素
描述:在有序(升序)的数组中插入一个数,使得插入的数组仍然有序
**/

void insert(int *a, int num) {
	printf("%d\n", num);
	int i=0, j=N+1;
	for ( ; i <= N; ++i) {
		if (num < *(a+i))
			break;			// 插入的数据记录大于数组中数据的位置
	}
	for ( ; j > i; --j) {
		*(a+j) = *(a+j-1);
	}
	*(a+i) = num;
}


int main(int argc, char const *argv[]) {
	int a[N+1], add_num;
	int *p;
	printf("输入十个数字:\n");
	for (int i = 0; i < N; i++)
		scanf("%d", &a[i]);
	printf("输入要插入的数字: ");
	scanf("%d", &add_num);

	insert(a, add_num);
	printf("插入后的数组为: ");
	for (int i = 0; i < N+1; ++i) {
		printf("%d ", a[i]);
	}
	printf("\n");
	return 0;
}

示例结果:

$ gcc ex025.c -o demo
$ ./demo
输入十个数字:
1
2
3
4
5
7
8
9
10
11
输入要插入的数字: 6
6
插入后的数组为: 1 2 3 4 5 6 7 8 9 10 11

案例ex26: 使用指针交换两个数组中的最大值

1 题目

函数:max()、swap()

功能:使用指针交换两个数组中的最大值

描述:

输入两个五个元素的数组,使用指针将两个数组中的最大值进行交换

并输出最大值交换之后的两个数组

2 思路

以下都使用指针来进行实现

  1. 找到最大值 创建 int *max(int *a) 函数,指针指向找出的最大值
  2. 交换最大值 创建 void swap(int *p1, int *p2) 找到的两个最大值进行交换,即进行指针指向的内容进行交换

3 代码

#include <stdio.h>
#include <stdlib.h>
#define N 5

/**
函数:max()、swap()
功能:使用指针交换两个数组中的最大值
描述:
输入两个五个元素的数组,使用指针将两个数组中的最大值进行交换
并输出最大值交换之后的两个数组
**/


int * max(int *a) {
	int * p = a;
	for (int i = 1; i < N; ++i) {
		if (*(a+i) > *p)
			p = a+i;
	}
	return p;
}

void swap(int *p1, int *p2) {
	*p1 = *p1 ^ *p2;
	*p2 = *p1 ^ *p2;
	*p1 = *p1 ^ *p2;
}


int main(int argc, char const *argv[]) {
	int a[N], b[N];
	int * max_a, * max_b;
	// 1. 初始化两个数组
	printf("输入数组 a 的5个数字:\n");
	for (int i = 0; i < N; ++i) {
		scanf("%d", (a+i));
	}
	printf("输入数组 b 的5个数字:\n");
	for (int j = 0; j < N; ++j) {
		scanf("%d", (b+j));
	}
	printf("\n数组 a 的5个数字为: ");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(a+i));
	}
	printf("\n数组 b 的5个数字为: ");
	for (int j = 0; j < N; ++j) {
		printf("%d ", *(b+j));
	}

	// 2. 找出各数组中的最大值
	max_a = max(a);
	max_b = max(b);
	printf("\n数组 a 的最大值:%d", *max_a);
	printf("\n数组 b 的最大值:%d", *max_b);

	// 3. 对两个最大值进行交换
	swap(max_a, max_b);
	printf("\n交换最大值之后的数组 a 的5个数字为:");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(a+i));
	}
	printf("\n交换最大值之后的数组 b 的5个数字为:");
	for (int j = 0; j < N; ++j) {
		printf("%d ", *(b+j));
	}
}

示例结果:

$ gcc ex026.c -o demo
yaojianguodeMacBook-Pro:C语言100题集合代码 yaojianguo$ ./demo
输入数组 a 的5个数字:
1
3
5
7
9
输入数组 b 的5个数字:
2
4
6
8
10

数组 a 的5个数字为: 1 3 5 7 9
数组 b 的5个数字为: 2 4 6 8 10
数组 a 的最大值:9
数组 b 的最大值:10
交换最大值之后的数组 a 的5个数字为:1 3 5 7 10
交换最大值之后的数组 b 的5个数字为:2 4 6 8 9

案例ex27: 输出二维数组有关值(二维数组的经典案例,非常重要)

1 题目

功能:输出二维数组有关值(二维数组的经典案例,非常重要)

描述:输出二维数组中的有关值,以及指向二维数组的指针变量的应用

2 思路

非常重要!非常重要!非常重要!

a+1 是二维数组 a 中序号为 1 的行的首地址(序号从0起算),而*(a+1) 并不是 a+1 单元的内容(值),因为 a+1 并不是一个变量的存储单元,也就谈不上他的内容了。*(a+1) 就是 a[1],而 a[1] 是一维数组名,所以也是地址,它指向 a[1][0]。a[1] 和 *(a+1) 都是二维数组中地址的不同表现形式

3 代码

#include <stdio.h>

/**
功能:输出二维数组有关值(二维数组的经典案例,非常重要)
描述:输出二维数组中的有关值,以及指向二维数组的指针变量的应用
**/


int main(int argc,  char const *argv[]) {
    int a[3][4]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
    printf("%d, %d\n", a, *a); 								// 0 行的首地址, 0 行 0 列元素地址
    printf("%d, %d\n", a[0], *(a+0));					// 0 行 0 列元素地址, 0 行 0 列元素地址
    printf("%d, %d\n", &a[0], &a[0][0]);			// 0 行的首地址, 0 行 0 列元素地址
    printf("%d, %d\n", a[1], a+1);						// 1 行 0 列的元素地址, 1 行首地址
    printf("%d, %d\n", &a[1][0], *(a+1)+0);		// 1 行 0 列的元素地址, 1 行 0 列元素地址
    printf("%d, %d\n", a[1][1], *(*(a+1)+1));	// 1 行 1 列的值,1 行 1 列的值
    getchar();
}

示例结果:

$ gcc ex027.c -o demo
$ ./demo
-302746704,-302746704
-302746704,-302746704
-302746704,-302746704
-302746688,-302746688
-302746688,-302746688
6,6

案例ex28: 输出二维数组任一行任一列值

1 题目

功能:输出二维数组任一行任一列值

描述:一个 3 行 4 列的数组,输入要显示数组元素的所在行数和列数,将在终端显示该数组元素的值

2 思路

熟悉ex027的案例,对上一个案例的简单应用

要彻底理解指针和二维数组的操作以及其内在的联系

3 代码

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

/**
功能:输出二维数组任一行任一列值
描述:一个 3 行 4 列的数组,输入要显示数组元素的所在行数和列数,将在终端显示该数组元素的值
**/

int main(int argc, char const *argv[]) {
    int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
    int *p, (*pt)[4], i, j;
    printf("数组内容为:");
    for (p = a[0]; p < a[0] + 12; p++) {
        if ((p - a[0]) % 4 == 0)
            printf("\n");
        printf("%4d",  *p);
    }
    printf("\n");
    printf("请输入想要获取的数字的位置: i=, j= \n");
    pt = a;
    scanf("i=%d, j=%d", &i, &j);

    printf("%d行%d列的值为;\na[%d, %d]=%d\n", i, j, i, j, *(*(pt + i) + j));
    getchar();
}

示例结果:

$ gcc ex028.c -o demo
$ ./demo
数组内容为:
   1   2   3   4
   5   6   7   8
   9  10  11  12
请输入想要获取的数字的位置: i=, j=
 i=1, j=2
1行2列的值为;
a[1, 2]=7

案例ex29: 将若干字符串按照字母顺序输出

1 题目

函数:sort()

功能:将若干字符串按照字母顺序输出

描述:实现对程序中几个字符串按照从小到大的顺序进行排序,并打印出来

2 思路

运用字符串数组的方式:

char * week[] = {};

将 week 传递到 sort() 函数,然后利用 C 语言提供的 strcmp() 进行字符类的比较

3 代码

#include <stdio.h>
#include <string.h>
#define N 7

/**
函数:sort()
功能:将若干字符串按照字母顺序输出
描述:实现对程序中几个字符串按照从小到大的顺序进行排序,并打印出来
**/


void sort(char *p[]) {
	char *temp;
	for (int i = 0; i < N; ++i) {
		for (int j = i+1; j < N; ++j) {
			if (strcmp(*(p+i), *(p+j)) > 0) {	// 比较大小,交换位置
				temp = *(p+i);
				*(p+i) = *(p+j);
				*(p+j) = temp;
			}
		}
	}
}


int main(int argc, char const *argv[]) {
	char * week[] = {
		"Monday",
		"Tuesday",
		"Wednesday",
		"Thursday",
		"Friday",
		"Saturday",
		"Sunday"
	};
	sort(week);
	printf("排序后的周为:\n");
	for (int i = 0; i < N; ++i) {
		printf("%s ", *(week+i));
	}
	getchar();
}

示例结果:

$ gcc ex029.c -o de
$ ./demo
排序后的周为:
Friday Monday Saturday Sunday Thursday Tuesday Wednesday

案例ex30: 用指向函数的指针比较大小

1 题目

函数:min() / max()

功能:用指向函数的指针比较大小

描述:实现输入两个整数后,打印较小和较大的那个数字(规定使用指向函数的指针实现)

2 思路

函数指针

  • 函数具有可赋值给指针的物理内存地址,一个函数的函数名就是一个指针,它指向函数的代码。一个函数的地址是该函数的进入点,也是调用函数的地址。函数的调用可以通过函数名,也可以通过指向函数的指针来调用。函数指针还允许将函数作为变元传递给其他函数。

  • 不带括号和变量列表的函数名,这可以表示函数的地址,正如不带下标的数组名可以表示数组的首地址。

  • 定义形式:

    // 类型 (*指针变量名)(参数列表);
    // 例如:
    int (*p)(int i,int j);
    
  • p是一个指针,它指向一个函数,该函数有2个整形参数,返回类型为int。p首先和*结合,表明p是一个指针。然后再与()结合,表明它指向的是一个函数。指向函数的指针也称为函数指针。

本案例中,利用指向函数的指针,在不同情况同一个指针指向不同的函数实现不同的功能

3 代码

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

/**
函数:min() / max()
功能:用指向函数的指针比较大小
描述:实现输入两个整数后,打印较小的那个数字(规定使用指向函数的指针实现)
**/

int min(int a, int b) {
    if (a < b)
        return a;
    else
        return b;
}

int max(int a, int b) {
    if (a > b)
        return a;
    else
        return b;
}

int main(int argc, char const *argv[]) {
    int(*p)();
    int a, b, max_v, min_v;

    printf("请你输入两个数字(如:a, b): \n");
    scanf("%d, %d", &a, &b);
    // 取小值
    p = min;
    min_v = (*p)(a, b);
    printf("min=%d\n", min_v);
    // 取大值
    p = max;
    max_v = (*p)(a, b);
    printf("max=%d\n", max_v);
    getchar();
}

示例结果:

$ gcc ex030.c -o demo
$ ./demo
请你输入两个数字(如:a, b):
1,5
min=1
max=5

$ ./demo
请你输入两个数字(如:a, b):
10,50
min=1
max=50

**案例ex31: 字符串的匹配 **

1 题目

函数:match()

功能:字符串的匹配

描述:

本例实现两个字符串的匹配操作,即在第一个字符串中查找是否存在第二个字符串。

如果字符串完全匹配,则提示”匹配“,并显示第二个字符串在第一个字符串中的开始位置。

否则:提示”不匹配“

2 思路

本案例自定义 match(char *B, char *A) 函数进行匹配,使用循环进行每个字符进行比较,从而找出是否包含子串

3 代码

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


/**
函数:match()
功能:字符串的匹配	
描述:
本例实现两个字符串的匹配操作,即在第一个字符串中查找是否存在第二个字符串。
如果字符串完全匹配,则提示”匹配“,并显示第二个字符串在第一个字符串中的开始位置。
否则:提示”不匹配“
**/


int match(char *B, char *A) {
    int i, j, start = 0;
    int lastB = strlen(B) - 1;
    int lastA = strlen(A) - 1;
    int endmatch = lastA;
    for (j = 0; endmatch <= lastB; endmatch++, start++)
    {
        if (B[endmatch] == A[lastA])
            for (j = 0, i = start; j < lastA && B[i] == A[j];)
                i++, j++;
        if (j == lastA)
        {
            return (start + 1); /*成功  */
        }

    }
    if (endmatch > lastB)
    {
        printf("字符串不匹配!");
        return  - 1;
    }
}


int main(int argc, char const *argv[]) {
    char s[] = "Computational advertising ecology"; // 计算广告生态
    char t[] = "advertising";
    int p = match(s, t);
    if (p !=  - 1)
    {
        printf("匹配!\n");
        printf("匹配的开始位置在: %d", p);
    }
    printf("\n");
    getchar();
}

示例结果:

$ gcc ex031.c -o demo
$ ./demo
匹配!
匹配的开始位置在: 15


案例ex32: 使用malloc()函数分配内存

1 题目

功能:使用malloc()函数分配内存

描述:

要求创建一个结构体类型的指针,其中包含两个成员,一个是整型,另外一个是结构体指针

使用 malloc() 函数分配一个结构体的内存空间,然后给这两个成员赋值并显示

2 思路

malloc() 函数的语法格式如下:

void *malloc(unsigned int size);

该函数的作用是在内存中的动态存储区域动态分配指定长度的存储空间。该函数返回一个指针,然后指向所分配存储空间的起始地址。 如果返回值 0,那么表示没有成功申请到内存空间。函数类型为 void * ,表示返回的指针不指向任何类型。

本例中,使用 malloc() 函数申请返回指向结构体的指针,利用该指针可以进行结构体成员的赋值和取值操作

st s = (struct stu*)malloc(sizeof(struct stu));

3 代码

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


/**
功能:使用malloc()函数分配内存
描述:
要求创建一个结构体类型的指针,其中包含两个成员,一个是整型,另外一个是结构体指针。
使用 malloc() 函数分配一个结构体的内存空间,然后给这两个成员赋值并显示
**/

typedef struct stu {
	int n;
	struct stu *next;	// 结构体成员,指针类型
}*st;

int main(int argc, char const *argv[]) {
	st s = (struct stu*)malloc(sizeof(struct stu)); 	// 开辟存储空间
	s->n = 1; 				// 成员 n 赋值
	s->next = NULL;			// 成员 next 赋值
	printf("成员的 n = %d, 成员 next = %d\n", s->n, s->next);
	return 0;
}

示例结果:

$ gcc ex032.c -o demo
$ ./demo
成员的 n = 1, 成员 next = 0

案例ex33: 调用calloc()函数动态分配内存存放若干数据

1 题目

功能:调用calloc()函数动态分配内存存放若干数据

返回值分配域的起始地址吗,如果分配失败返回 0


理解malloc() 和 calloc() 异同点

2 思路

  • calloc() 函数 的语法格式如下:

    void * calloc(unsigned n, unsigned size);
    

    在内存中动态分配 n 个长度为 size 的连续内存空间数组,calloc() 函数会返回一个指针 该指针指向动态分配的连续内存空间地址。 当分配错误的时候,会返回 0

  • malloc() 和 calloc() 异同点

    • 共同点: 都为了分配存储空间, 它们返回的是 void * 类型,也就是说如果我们要为int或者其他类型的数据分配空间必须显式强制转换

    • 不同点: malloc() 1个形参,因此如果是数组,必须由我们计算需要的字节总数作为形参传递 用malloc只分配空间不初始化,也就是依然保留着这段内存里的数据, calloc() 2个形参,因此如果是数组,需要传递个数和数据类型 而calloc则进行了初始化,calloc分配的空间全部初始化为0,这样就避免了可能的一些数据错误

3 代码

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


/**
功能:调用calloc()函数动态分配内存存放若干数据
返回值分配域的起始地址吗,如果分配失败返回 0
**/


int main(int argc, char const *argv[]) {
	int n;
	int *p, *q;
	printf("输入数据的个数:\n");
	scanf("%d", &n);
	p = (int *)calloc(n, sizeof(int));	// 分配内存空间,并且会进行初始化
	printf("为 %d 个数据分配内存空间 \n", n);
	for (q = p; q < p+n; ++q) {
		scanf("%d", q);
	}

	printf("给 p 指向的一段内存空间存储的内容是:\n");
	for (int i = 0; i < n; ++i) {
		printf("%d ", *(p+i));
	}
	printf("\n");
}

示例结果:

$ gcc ex033.c -o demo
$ ./demo
输入数据的个数:
5
为 5 个数据分配内存空间
1
5
6
8
9
给 p 指向的一段内存空间存储的内容是:
1 5 6 8 9

案例ex34: 为具有 5 个数组元素的数组分配内存

1 题目

功能:为具有 5 个数组元素的数组分配内存

描述:为具有 5 个元素的数组动态分配内存,并赋值输出

2 思路

使用 calloc() 函数为数组的 5 个元素进行分配存储空间,然后进行赋值

3 代码

#include <stdio.h>
#include <stdlib.h>
#define N 5


/**
功能:为具有 5 个数组元素的数组分配内存
描述:为具有 5 个元素的数组动态分配内存,并赋值输出
**/


int main(int argc, char const *argv[]) {
	int * p;
	p = (int *)calloc(N, sizeof(int));
	printf("看使用 calloc() 函数后,初始化的内容:\n");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(p+i));
	}
	getchar();
	// 赋值
	for (int i = 0; i < N; ++i) {
		*(p+i) = i*3;
	}
	// 输出
	printf("初始化后的数组的内容:\n");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(p+i));
	}	
	printf("\n");
}

示例结果:

$ gcc ex034.c -o demo
$ ./demo
看使用 calloc() 函数后,初始化的内容:
0 0 0 0 0
初始化后的数组的内容:
0 3 6 9 12

案例ex35: 为二维数组动态分配内存

1 题目

功能:为二维数组动态分配内存

描述:为二维数组动态分配内存,然后输出并释放内存

2 思路

  • 在C语言中,一维数组是通过 malloc() 函数动态分配空间来实现的,动态的二维数组也能够通过malloc()函数动态分配空间来实现。实际上,C语言中没有二维数组,至少对二维数组没有直接的支持,取而代之的是“数组的数组”,二维数组能够看成是由指向数组的指针构成的数组。
  • 对于一个二维数组p[i][j],编译器通过公式 *(*(p+i)+j) 求出数组元素的值,其中,p+i表示计算行指针;*(p+i)表示具体的行,是指针,指向该行首元素地址 *(*(p+i)+j 表示得到具体元素的地址;*(*(p+i)+j)表示得到元素的值。基于这个原理,通过分配一个指针数组,再对指针数组的每一个元素分配空间实现动态的分配二维数组

案例中实现的步骤 1.定义二维指针

int **p; 		// 二维数组指针

2.分配行动态空间

p = (int **)malloc(sizeof(int *[M])); 	// 指向指针的指针

3.再为每一行的每一列进行动态分配

*(p+i) = (int *)malloc(sizeof(int[N]));

3 代码

#include <stdio.h>
#include <stdlib.h>
#define M 3
#define N 5

/**
功能:为二维数组动态分配内存
描述:为二维数组动态分配内存,然后输出并释放内存
**/

int main(int argc, char const *argv[]) {
	int **p; 		// 二维数组指针
	p = (int **)malloc(sizeof(int *[M])); 	// 指向指针的指针
	for (int i = 0; i < M; ++i) {
		*(p+i) = (int *)malloc(sizeof(int[N]));
		for (int j = 0; j < N; ++j) {
			*(*(p+i)+j) = i + j;
		}
	}

	// 输出内容
	printf("给二维数组分配空间后,内存的内容是:\n");
	for (int i = 0; i < M; ++i) {
		for (int j = 0; j < N; ++j) {
			printf("%d \t", *(*(p+i)+j));
		}
		putchar('\n');
	}
}

示例结果:

$ gcc ex035.c -o demo
$ ./demo
给二维数组分配空间后,内存的内容是:
0 	1 	2 	3 	4
1 	2 	3 	4 	5
2 	3 	4 	5 	6

案例ex36: 商品信息的动态存放

1 题目

功能:商品信息的动态存放

描述:

创建一个商品的结构体

动态分配一块内存区域,存放一个商品信息

2 思路

  • 定义一个商品信息的结构体类型,同时声明一个结构体类型的指针COMM
  • 调用 malloc() 函数分配空间,地址存放在指针变量 commodity 中
  • 利用指针变量访问该地址空间中的每个成员数据,并为成员赋值,主要要使用 "->" 去访问,例如:
COMM commodity = (struct commodity *) malloc(sizeof(struct commodity));
commodity->num = 1011;
commodity->name = "计算广告生态";
commodity->count = 10001;
commodity->price = 15000.1;

3 代码

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


/**
功能:商品信息的动态存放
描述:创建一个商品的结构体, 动态分配一块内存区域,存放一个商品信息
**/


typedef struct commodity {	// 结构体定义
	int num; 									// 编号
	char *name; 							// 商品名称
	int count;  							// 商品数量
	double price; 						// 商品单价
}*COMM;


int main(int argc, char const *argv[]) {
	COMM commodity = (struct commodity *) malloc(sizeof(struct commodity));
	commodity->num = 1011;
	commodity->name = "计算广告生态";
	commodity->count = 10001;
	commodity->price = 15000.1;
	printf("编号:%d\n商品名称:%s\n商品数量:%d\n商品单价:%f\n",	
		commodity->num, commodity->name, commodity->count, commodity->price);
}

示例结果:

$ gcc ex036.c -o demo
$ ./demo
编号:1011
商品名称:计算广告生态
商品数量:10001
商品单价:15000.100000

案例ex37: 用不带参数的宏定义求平行四边形面积

1 题目

功能:用不带参数的宏定义求平行四边形面积

描述:利用不带参数的宏的形式(一般宏大写字母,以便与其他的操作符进行区别)

2 思路

不带参数的宏名定义如下:

#define 宏名 字符串

一般情况下 "#" 表示这是一条预处理命令,宏名是一个标识符,必须符合 C 语言规定 字符串可以是常数、表达式、格式字符串等 后面几节分别就这几种进行讲解

3 代码

#include <stdio.h>
#define A  8  // 定义宏,设置底边的长度
#define H  6  // 定义宏,设置高的长度

/**
函数:fun()
功能:用不带参数的宏定义求平行四边形面积
描述:利用不带参数的宏的形式(一般宏大写字母,以便与其他的操作符进行区别)
**/

int main(int argc, char const *argv[]) {
    int area;												// 存储平行四边形面积
    area = A * H;										// 计算平行四边形面积
    printf("面积 = %d\n", area);		 // 输出面积值
}

示例结果:

$ gcc ex037.c -o demo
$ ./demo
面积 = 48

案例ex38: 使用宏定义实现数组值的互换

1 题目

功能:使用宏定义实现数组值的互换

描述:定义一个宏 swap(a, b),以实现两个整数的交换,并利用它将一维数组 a 和 b 进行交换

2 思路

宏关于函数的运用 一般形式:

#define 宏名(参数表) 字符串函数定义
  • 对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替 #define 命令行中的形参
  • 在宏定义时,在宏名与带参数的括号之间不可以加空格,否则将空格以后的字符都作为替代字符串的一部分
  • 在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义

3 代码

#include <stdio.h>
#define N 10
#define swap(a, b) {int temp; temp=a;a=b;b=temp;} // 宏swap(a,b)进行两个整数的交换

/**
功能:使用宏定义实现数组值的互换
描述:定义一个宏 swap(a, b),以实现两个整数的交换,并利用它将一维数组 a 和 b 进行交换
**/

int main(int argc, char const *argv[]) {
	int a[N], b[N];
	printf("请输入一个数组a:\n");
	for (int i = 0; i < N; ++i) {
		scanf("%d", a+i);
	}
	printf("请输入一个数组b:\n");
	for (int i = 0; i < N; ++i) {
		scanf("%d", b+i);
	}

	printf("数组a的内容是:\n");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(a+i));
	}
	printf("\n");
	printf("数组b的内容是:\n");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(b+i));
	}

	// 交换数组a 和 数组b的内容
	for (int i = 0; i < N; ++i) {
		swap(*(a+i), *(b+i));
	}

	printf("\n");
	printf("交换后数组a的内容是:\n");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(a+i));
	}
	printf("\n");
	printf("交换后数组b的内容是:\n");
	for (int i = 0; i < N; ++i) {
		printf("%d ", *(b+i));
	}
}

示例结果:

$ gcc ex038.c -o demo
$ ./demo
请输入一个数组a:
1
3
5
7
9
11
13
15
17
19
请输入一个数组b:
2
4
6
8
10
12
14
16
18
20
数组a的内容是:
1 3 5 7 9 11 13 15 17 19
数组b的内容是:
2 4 6 8 10 12 14 16 18 20
交换后数组a的内容是:
2 4 6 8 10 12 14 16 18 20
交换后数组b的内容是:
1 3 5 7 9 11 13 15 17 19

案例ex39: 编写头文件包含圆面积的计算公式

1 题目

功能:编写头文件包含圆面积的计算公式

描述:

计算圆的面积,宏定义存储在一个头文件中

输入半径就可以得到面积

2 思路

使用不同的文件需要包含不同的 #include 指令,包含两种格式

#include <文件名>
#include "文件名"
  • 需要注意的是,这两种格式的区别是

    • 用尖括号时,系统到存放C库函数头文件所在的目录中寻找要包含的文件,这种称为标准方式
    • 用双引号时,系统先在用户当前目录中寻找要包含的文件,若找不到,再到存放C库函数头文件所在的目录中寻找要包含的文件
  • 如果为调用库函数用 #include 命令来包含相关的头文件,则用尖括号,可以节省査找的时间

  • 如果要包含的是用户自己编写的文件,一般用双引号,用户自己编写的文件通常是在当前目录中

如果文件不在当前目录中,双引号可给出文件路径

3 代码

主函数代码:

#include <stdio.h>
#include "ex039_area.h"

/**
功能:编写头文件包含圆面积的计算公式
描述:
计算圆的面积,宏定义存储在一个头文件中
输入半径就可以得到面积
**/


int main(int argc, char const *argv[]) {
    float r;							// 定义园的半径
    printf("请输入半径:\n");
    scanf("%f",&r);
    printf("面积 =%.2f \n",area(r));	// 调用 ex039_area.h 中的 area函数
}

ex039_area.h:

#define PI 3.14
#define area(r) PI*(r)*(r)

示例结果:

$ gcc ex039.c -o demo
$ ./demo
请输入半径:
3
面积 =28.26
~~~~~~~~~~~~~~~~~~~~
$ ./demo
请输入半径:
10
面积 =314.00

案例ex40: 利用宏定义求偶数和

1 题目

功能:利用宏定义求偶数和

描述:

定义一个宏实现求 1~100 的偶数和

定义一个宏判断一个数是否为偶数

2 思路

1、先熟悉带参数的宏已经参数宏利用其它的宏定义

#define TRUE 1
#define FALSE 0
#define EVEN(x) (((x)%2==0)?TRUE:FALSE)

2、要点 在累加求和过程中需要不断判断数据是否为偶数,因此要创建带参数的宏 把判断偶数的过程定义为常量,由于C语言中不提供逻辑常量,因此自定义宏 TRUE 和 FALSE,表示1和0 因此,判断偶数的宏又可以演变为下面的形式:

3 代码

#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define EVEN(x) (((x)%2==0)?TRUE:FALSE)

/**
功能:利用宏定义求偶数和
描述:
定义一个宏实现求 1~100 的偶数和
定义一个宏判断一个数是否为偶数
**/

int main(int argc, char const *argv[]) {
    int sum = 0;
    for(int i = 1; i <= 100; ++i) {
        if(EVEN(i))	
            sum+=i;	
    }
    printf("SUM = %d\n",sum);	
}

示例结果:

$ gcc ex040.c -o demo
$ ./demo
SUM = 2550

案例ex41: 利用文件包含设计输出模式

1 题目

功能:利用文件包含设计输出模式

描述:

在程序设计时需要很多输出格式,如整型、实型及字符型等,在编写稈序时会经常使用这些输出格式 如果经常书写这些格式会很繁琐,要求设计一个头文件,将经常使用的 输出模式都写进头文件中,方便编写代码

2 思路

本稈序中仅举一个简单的例子,将整型数据的输出写入到头文件中,并将这个头文件 命名为 ex041_format.h 声明整型数据并输出的形式如下:

#define INTEGER(d) printf("%4d\n",d)

3 代码

主函数:

#include <stdio.h>
#include "ex041_format.h"	

/**
功能:利用文件包含设计输出模式
描述:
在程序设计时需要很多输出格式,如整型、实型及字符型等,在编写稈序时会经常使用这些输出格式
如果经常书写这些格式会很繁琐,要求设计一个头文件,将经常使用的
输出模式都写进头文件中,方便编写代码
**/

int main(int argc, char const *argv[]) {
    int d;					
    printf("请输入一个整数:");	
    scanf("%d", &d);		
    INTEGER(d);		// 使用宏定义的函数
}

ex041_format.h

#define INTEGER(d) printf("计算结果: %4d\n",d)

示例结果:

$ gcc ex041.c -o demo
$ ./demo
请输入一个整数:10
计算结果:   10

案例ex42: 使用条件编译隐藏密码

1 题目

功能:使用条件编译隐藏密码

描述:一般输入密码时都会用拿号来替代,用以增强安全性。要求设置一个宏,规定宏体为 1,在正常情况下密码显示为审号的形式,在某些特殊的时候,显示为字符串。运行结果

2 思路

C 语言预编译命令 #if··· #else··· #endif

这个方法一般可以用来调试的时候用,也可以作为控制语句进行使用。有时候串口打印信息太多,一条条注释就很麻烦,于是就用这种方法,定义个宏变量,判断宏变量的条件,来达到改变宏变量的值控制那些代码编译

指令格式为:

#if
	语句段1
#else
	语句段2
#endif

对于一个字符串要求有两种输出形式 一种是原样输出 另一种是用相同数目输出 可以通过选择语句来实现,但是使用条件编译指令可以在编译阶段就决定要怎样操作

3 代码

#include <stdio.h>
#define PWD 1

/**
功能:使用条件编译隐藏密码
描述:一般输入密码时都会用拿号来替代,用以增强安全性。要求设置一个宏,规定宏体为
1,在正常情况下密码显示为审号的形式,在某些特殊的时候,显示为字符串。运行结果
**/

int main(int argc, char const *argv[]) {
    char *s="mrsoft";
#if PWD	
    printf("******\n");
#else					
    printf("%s\n",s);	
#endif
}

示例结果:

$ gcc ex042.c -o demo
$ ./demo
******

案例ex43: 关闭所有打开的文件

1 题目

功能:用fgetc函数从键盘逐个输入字符,然后用fputc函数写到磁盘文件中

描述:

用 fgetc 函数从键盘逐个输入字符,然后用 fputc函数写到磁盘文件即可

2 思路

  1. 用来存储数据的文件名可以在fopen函数中直接写成字符串常量形式(如指定"1"),也可以在程序运行时由用户临时指定。本程序采取的方法是由键盘输入文件名。为此设立一个字符数组filename,用来存放文件名。运行时,从键盘输入磁盘文件名"ex043_file.dat", 操作系统就新建立一个磁盘文件ex043_file.dat,用来接收程序输出的数据
  2. 用fopen函数打开一个"只写"的文件("w"表示只能写入不能从中读数据),如果打开文件成功,函数的返回值是该文件所建立的信息区的起始地址,把它赋给指针变量fp(fp已定义为指向文件的指针变量)。如果不能成功地打开文件,则在显示器的屏幕上显示"无法打开此文件",然后用exit函数终止程序运行
  3. exit是标准C的库函数,作用是使程序终止,用此函数时在程序的开头应包含 <stdlib.h> 头文件
  4. 用getchar函数接收用户从键盘输入的字符。注意每次只能接收一个字符。今输入字符串"公众号:计算广告生态"是用来向程序表示:输入的字符串到此结束。用什么字符作为结束标志是人为的,由程序指定的,也可以用别的字符(如或其他字符)作为结束标志。但应注意:如果字符串中包含"#",就不能用"# "作结束标志
  5. 执行过程是:先从键盘读入一个字符,检查它是否如果是,表示字符串已结束,不执行循环体。如果不是'#',则执行一次循环体,将该字符输出到磁盘文件filel.datₒ然后在屏幕上显示出该字符,接着再从键盘读入一个字符。如此反复,直到读入'#'字符为止。这时,程序已将"公众号:计算广告生态"写到以"filel. dat"命名的磁盘文件中了,同时在屏幕上也显示出了这些字符,以便核对。
  6. ex043_file.dat 中是否确实存储了这些内容,可以在资源管理器中,按记事本的打开方式打开文件,或者在其他系统有其他查看方式

3 代码

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

/**
功能:关闭所有打开的文件
描述:
用 fgetc 函数从键盘逐个输入字符,然后用 fputc函数写到磁盘文件即可
**/

int main(int argc, char const *argv[]) {
	FILE * fp;
	char ch, filename[10];
	printf("请输入要操作的文件名:\n");
	scanf("%s", filename);

	if ((fp = fopen(filename, "w")) == NULL) { 	// 打开输入文件并使 fp 指向此文件	
		printf("无法打开此文件!\n");
		exit(0); 										// 终止程序
	}
	ch = getchar();								// 用来接收最后输入的回车符
	printf("请输入一个准备存储到磁盘的字符串(以'#'结束)\n");
	ch = getchar();								// 用来接收从键盘输入的第一个字符
	while (ch != '#') {						// 当输入"#"时结束循环
		fputc(ch, fp);							// 用来向磁盘输出第一个字符
		putchar(ch);								// 将输出的字符显示在屏幕上
		ch = getchar();							// 接收从键盘输入的一个字符
	}
	fclose(fp);										// 关闭文件
	putchar(10);									// 向屏幕输出一个换行符
	return 0;
}

示例结果:

$ gcc ex043.c -o demo
$ ./demo
请输入要操作的文件名:
ex043_file.dat
请输入一个准备存储到磁盘的字符串(以'#'结束)
公众号:计算广告生态
公众号:计算广告生态
#

文件中的显示:

ex043_file.dat:

公众号:计算广告生态

案例ex44: 将文件中的内容从一个文件拷贝到另外一个文件

1 题目

功能:将文件中的内容从一个文件拷贝到另外一个文件

描述:将上一个案例中的ex043_file.dat 赋值内容到 ex044_file.data

2 思路

1、在访问磁盘文件时,是**逐个字符(字节)**进行的,为了知道当前访问到第几个字节,系统用 "文件读写位置标记" 来表示当前所访问的位置。开始时“文件读写位置标记”指向第1个字节, 每访问完一个字节后,当前读写位置就指向下一个字节,即当前读写位置自动后移。

2、为了知道对文件的访问是否完成,只须看文件读写位置是否移到文件的末尾。用feof函数可以检查到"文件读写位置标记"是否移到文件的末尾,即磁盘文件是否结束。程序第 26 行中的feof(in)是检查in所指向的文件是否结束。如果是,则函数值为1(真),否则为0(假),也就是“ !feof(in) ”为真,在while循环中检査“!feof(in)”为真,就执行循环体。

3、运行结果是将file.dat文件中的内容复制到file2.dat中去。打开这两个文件,可以看到 filel. dat 和 file2. dat 的内容都是:

This is the first message
copy to another file

4、以上程序是按文本文件方式处理的。也可以用此程序来复制一个二进制文件,只须将两个fopen函数中的“r”和“w”分别改为“rb”和“wb”即可。

5、C 系统已把fputc和fgetc函数定义为宏名putc和getc:

# define putc(ch, fp) fputc(ch, fp)
# define getc(fp) fgetc(fp)

这是在 <stdio.h> 中定义的。因此,在程序中用putc和fputc作用是一样的,用getc和fgetc 作用是一样的。在使用的形式上,可以把它们当作相同的函数对待。

3 代码

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

/**
功能:将文件中的内容从一个文件拷贝到另外一个文件
描述:将上一个案例中的ex043_file.dat 赋值内容到 ex044_file.dat
**/

int main(int argc, char const *argv[]) {
	FILE *in, *out;										// 指向文件的变量
	char ch, infile[20], outfile[20];	// 定义的两个字符数组,分别存放两个数据文件名
	printf("输入读入文件的名称(ex043_file.dat):");
	scanf("%s", infile);							// 输入第一个要读取文件的文件名
	printf("输入输出文件的名称(ex044_file.dat):");
	scanf("%s", outfile);							// 输入第一个要读取文件的文件名
	
	if ((in = fopen(infile, "r"))==NULL) {	 // 打卡输入文件
		printf("无法打开输入文件..\n");
		exit(0);
	}
	if ((out = fopen(outfile, "w"))==NULL) {	 // 打卡输出文件
		printf("无法打开输出文件..\n");
		exit(0);
	}	
 	
	while(!feof(in)) {					// 如果未遇到输入文件的结束标志,每次访问完一个字节后自动指向下一个字节
		ch = fgetc(in);						// 从输入文件中读取一个
		fputc(ch, out);						// 将 ch 写到 outfile 中
		putchar(ch); 							// 显示到屏幕上
	}
	putchar(10);								// 最后进行换行
	fclose(in);									// 关闭输入文件
	fclose(out);								// 关闭输出文件
	return 0;
}

示例结果:

$ gcc ex044.c -o demo
$ ./demo
输入读入文件的名称(ex043_file.dat):ex043_file.dat
输入输出文件的名称(ex044_file.dat):ex044_file.dat
This is the first message
copy to another file

原来文件中的内容:

This is the first message copy to another file

赋值过去的文件内容:

This is the first message
copy to another file

最后

在这里给大家准备了几百本的互联网技术类书籍,需要的来下载吧!mp.weixin.qq.com/s/KAYLiHFc5… 有任何问题,欢迎随时交流