C语言经典88案例,我文科妹妹说她都学会了!

代码

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

/**
函数:fun()
功能:将字符串转换为一个整数

描述:
【不能使用C语言提供的字符串函数】
输入:字符串"-1234"
输出:整型 -1234
**/

long fun(char p) {
int r = 0; //数字个数
long res = 0L; // 转化后的数字
int pos = 1; // 位数
10 *100 …
int size = strlen§; // 字符串长度
if (p[0] == ‘-’){
r = size - 1;
} else {
r = size;
}
// 从前往后转换的话,需要分情况去计算。即:不是负数的话从p[0] 和 如果是负数的话需要从p[1]开始
// 所以,可以从后往前计算,循环次数是 r
for (int i = 0; i < r; ++i) {
res += (p[size-1-i]-48)*pos;
pos *= 10;
}
return p[0]==’-’?-res:res;
}

int main(int argc, char const *argv[]) {
char s[6];
printf("Enter a string: ");
gets(s);
long res = fun(s);
printf(“Convert Result: %ld\n”, res);
return 0;
}
示例结果:

$ gcc ex1.c -o demo
$ ./demo
Enter a string: -1234
Convert Result: -1234
$ ./demo
Enter a string: 9089
Convert Result: 9089
案例ex02: 将M行N列的二维数组中的字符数据,按列的顺序依次放到一个字符串中
1 题目

编写:fun()

功能:将M行N列的二维数组中的字符数据,按列的顺序依次放到一个字符串中

例如:

二维数组中的数据为:

W W W W

S S S S

H H H H

则字符串中的内容是:WSHWSHWSH

2 思路

第一层循环按照列数进行,第二层循环按照行数

然后依次提出每一列的字符

3 代码

为了熟悉二维数组的指针表示,部分代码给出了数组表示和指针表示

#include<stdio.h>
#include<string.h>
#define M 3
#define N 4
/**
编写:fun()
功能:将M行N列的二维数组中的字符数据,按列的顺序依次放到一个字符串中

例如:
二维数组中的数据为:
W W W W
S S S S
H H H H
则字符串中的内容是:WSHWSHWSH
**/

// 0 1 2 3
// 0 W W W W
// 1 S S S S
// 2 H H H H

char *fun(char s[M][N], char res) {
int t = 0;
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) {
res[t++] = s[j][i];
// res[t++] = ((a
i)+i); // 指针表示
}
}
res[t] = ‘\0’;
return res;
}

int main(int argc, char const argv[]) {
char a[M][N] = {‘M’, ‘M’, ‘M’, ‘M’, ‘S’, ‘S’, ‘S’, ‘S’, ‘H’, ‘H’, ‘H’, ‘H’};
int size_res = M
N;
char res[size_res];
printf(“二维数组中元素:\n”);
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
printf("%c\t", a[i][j]);
// printf("%c\t", ((a*i)+j)); // 指针表示
}
printf("\n");
}

printf("按列的顺序依次:\n%s\n", fun(a, res));

}
示例结果:

$ gcc ex002.c -o demo
$ ./demo
二维数组中元素:
M M M M
S S S S
H H H H
按列的顺序依次:
MSHMSHMSHMSH
案例ex03: 统计一行字符串单词的个数,作为函数值返回
1 题目

函数:fun()

功能:统计一行字符串单词的个数,作为函数值返回

一行字符串在主函数中输入,规定所有单词都是由小写字母组成,单词之间由若干空格隔开,一行的开始没有空格

2 思路

逐个字符进行判断是否为空

下面“空开处”指的是一个空格或者若干空格隔开单词的说法

开头无空格,故需要判断结尾有没有空开出,如果有,直接计算空开出就是单词数,如果没有需要单词数加1
上述1中的空开出需要做处理,由于单词间由若干空格隔开,故判断一个空格的前一个是否为空格,如果不是,数量加1;如果是,不做处理
3 代码

#include<stdio.h>
#include<string.h>
#define M 3
#define N 4
/**
函数:fun()
功能:统计一行字符串单词的个数,作为函数值返回

一行字符串在主函数中输入,规定所有单词都是由小写字母组成,单词之间由若干空格隔开,一行的开始没有空格
**/

int fun(char s) {
int cnt = 0; // 单词个数
int i = 0;
while(
(s+i)!=’\0’) {
if (*(s+i) == ’ ’ && (s+i-1) != ’ ') {
cnt += 1;
}
++i;
}
if (
(s+i-1) != ’ '){ // 如果单词结尾没有空格,则单词数需要空开数+1
return cnt + 1;
}
return cnt;
}

int main(int argc, char const *argv[]) {
char s[] = “hello world i am c language”;
printf(“字符串内容:%s\n”, s);
printf(“单词个数为:%d\n”, fun(s));
}
示例结果:

$ gcc ex003.c -o demo
$ ./demo
字符串内容:hello world i am c language
单词个数为:6
案例ex04: 统计各个年龄阶段的人数
1 题目

函数:fun()

功能:统计各个年龄阶段的人数

描述:

N个年龄通过调用随机函数获得,并存放在主函数的age中
要求函数把0-9岁年龄段的放在d[0]中,把10-19岁年龄段的放在d[1]中,依次类推。把100岁及以上的放在d[10]中

结果在主函数中输出

2 思路

随机使用 rand() 函数,头文件为#include <stdlib.h>

rand()函数是按指定的顺序来产生整数,因此每次执行上面的语句都打印相同的两个值,所以说C语言的随机并不是真正意义上的随机,有时候也叫伪随机数,使用 rand() 生成随机数之前需要用随机发生器的初始化函数 srand(unsigned seed)(也位于 stdlib.h 中) 进行伪随机数序列初始化,seed 又叫随机种子,通俗讲就是,如果每次提供的 seed 是一样的话,最后每一轮生成的几个随机值也都是一样的,因此叫伪随机数,所以需要每次提供不同的 seed 达到完全的随机,我们通常用时间函数 time(NULL) 作为 seed ,因为时间值每秒都不同,但是在此题中使用不到time这个工具

3 代码

#include <stdio.h>
#include <stdlib.h>
#define M 11
#define N 100

/**
函数:fun()
功能:统计各个年龄阶段的人数
描述:
N个年龄通过调用随机函数获得,并存放在主函数的age中
要求函数把0-9岁年龄段的放在d[0]中,把10-19岁年龄段的放在d[1]中,依次类推。把100岁及以上的放在d[10]中
结果在主函数中输出
**/

void fun(int age, int d) {
for (int i = 0; i < N; ++i) {
if (
(age+i)<100) {
d[(
(age+i))/10] += 1;
} else {
d[M-1] += 1;
}
}
}

int main(int argc, char const *argv[]) {
int age[N]; // 100个用户
int d[M]={0}; // 11个年龄段
for (int i = 0; i < N; ++i) {
*(age+i) = rand()%121; // 设定年龄的范围是0-120
}
fun(age, d);
printf(“各年龄阶段人数数量:\n”);
for (int i = 0; i < M; ++i) {
printf("%d “, d[i]);
}
printf(”\n");
}
示例结果:

$ gcc ex004.c -o demo
$ ./demo
各年龄阶段人数数量:
10 9 8 4 10 8 7 7 6 11 20
案例ex05: 删除一维数组中所有相同的数,使之只剩一个。
1 题目

函数:fun()

功能:删除一维数组中所有相同的数,使之只剩一个。

描述:数组中的数据已经按照从小到大排列,函数返回删除后数组中元素的个数
举例:

一维数组中的数据是:2,2,2,2,3,3,4,4,5,6,6,6,7,7,8,9,9,9,10,10

删除后数组中的内容是:2,3,4,5,6,7,8,9,10

2 思路

初始化没有重复元素最右方的指针 a

当前元素与前一个元素进行比较,如果相同,则调到下一个,否则指针a+1

3 代码

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

/**
函数:fun()
功能:删除一维数组中所有相同的数,使之只剩一个。
描述:数组中的数据已经按照从小到大排列,函数返回删除后数组中元素的个数
举例:
一维数组中的数据是:2,2,2,2,3,3,4,4,5,6,6,6,7,7,8,9,9,9,10,10
删除后数组中的内容是:2,3,4,5,6,7,8,9,10
**/

int fun(int s) {
int a = 1;
for (int i = 1; i < N; ++i) {
if (
(s+i) != *(s+i-1)) { // 当前元素与前一个元素进行比较,如果相同,则调到下一个,否则a+1
*(s+a) = *(s+i);
a++;
}
}
return a;
}

int main(int argc,char const *argv[]) {
int s[N] = {2,2,2,2,3,3,4,4,5,6,6,6,7,7,8,9,9,9,10,10};
int cnt = fun(s);
printf(“删除后的数组元素个数为:%d\n”,cnt);
}
示例结果:

$ gcc ex005.c -o demo
$ ./demo
删除后的数组元素个数为:9
案例ex06: 移动字符串中内容
1 题目

函数:fun()

功能:移动字符串中内容

描述:移动规则如下:把第1到第m个字符,平移到字符串的最后,把m+1到最后的字符移到字符串的前部

举例:字符串原有内容为ABCDEFGHIJK,m的值为3,则移动后,字符串中的内容应该是DEFGHIJKABC

2 思路

为了不产生额外的空间复杂度,本次解决将一位一位移动

将数组第一个位置的元素保存到一个临时变量temp中,从第二位开始集体向左移动,最后将temp元素保存到最后一位

循环 m 次,从而达到最后的效果

3 代码

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

/**
函数:fun()
功能:移动字符串中内容
描述:移动规则如下:把第1到第m个字符,平移到字符串的最后,把m+1到最后的字符移到字符串的前部。
举例:字符串原有内容为ABCDEFGHIJK,m的值为3,则移动后,字符串中的内容应该是DEFGHIJKABC
**/

void fun(char *s, int m) {
int temp;
for (int i = 0; i < m; ++i) {
temp = s[0];
for (int j = 1; j < N; ++j) {
s[j-1] = s[j];
}
s[N-1] = temp;
}
}

int main(int argc, char const *argv[]) {
char s[N] = “ABCDEFGHIJ”;
int m = 3;
printf(“移动前的字符串:%s\n”, s);
fun(s, m);
printf(“移动后的字符串:%s\n”, s);
}
示例结果:

$ gcc ex006.c -o demo
$ ./demo
移动前的字符串:ABCDEFGHIJ
移动后的字符串:DEFGHIJABC
案例ex07: 求数字的低n-1位的数
1 题目

函数:unsigned fun(unsigned w)

功能:求数字的低n-1位的数

描述:w 是一个大于10的无符号整数,若 w 是 n(n>=2)位的整数,函数求出来w的低n-1位的数作为函数值返回

举例:w 值为5923,则函数返回 923

2 思路

两步走:

先判断当前无符号整数的位数,记录位数*10。例如:如果有三位,那么记录time=100
根据time计算后 n-1 位,即:w-((w/time)*time)
3 代码

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

/**
函数:unsigned fun(unsigned w)
功能:求数字的低n-1位的数
描述:w 是一个大于10的无符号整数,若 w 是 n(n>=2)位的整数,函数求出来w的低n-1位的数作为函数值返回
举例:w 值为5923,则函数返回 923
**/

unsigned fun(unsigned w) {
// 先判断数字的位数
int temp_w = w;
int time = 1; // 位数10的指数次
while(temp_w > 0) {
time*=10;
temp_w = temp_w/10;
}
time = time/10;
// 计算返回
return w-((w/time)*time);
}

int main(int argc, char const *argv[]) {
int w;
printf(“请一个大于10的无符号整数:”);
scanf("%d", &w);
printf(“无符号整数低n-1位的数为:%d\n”, fun(w));
}
示例结果:

$ gcc ex007.c -o demo
$ ./demo
请一个大于10的无符号整数:12345
无符号整数低n-1位的数为:2345
$ ./demo
请一个大于10的无符号整数:765432
无符号整数低n-1位的数为:65432
案例ex08: 使数组的左下三角元素中的值乘以n
1 题目

函数:fun(int a[][N], int n)

功能:使数组的左下三角元素中的值乘以n

描述:程序定义了 N*N 的二维数组,并在主函数中自动赋值。

举例:
若 n 的值为3,a数组中的值为
1 9 7
3 9 7
2 3 8
则返回主程序后 a 数组中的值应该为
3 9 7
9 27 7
6 9 24

2 思路

利用二重循环解决

在第二层需要进行一点注意的地方

3 代码

include <stdio.h>

include <stdlib.h>

define N 3

/**
函数:fun(int a[][N], int n)
功能:使数组的左下三角元素中的值乘以n
描述:程序定义了 N*N 的二维数组,并在主函数中自动赋值。
举例:
若 n 的值为3,a数组中的值为
1 9 7
3 9 7
2 3 8
则返回主程序后 a 数组中的值应该为
3 9 7
9 27 7
6 9 24
*/

void fun(int a[][N], int n) {
for (int i = 0; i < N; ++i) {
for (int j = 0; j <= i; ++j) {
a[i][j] = a[i][j] * n;
}
}
}

int main(int argc, char const *argv[]) {
int a[N][N] = {{1,9,7}, {3,9,7}, {2,3,8}};
int n = 3;

printf("原数组为:\n");
for (int i = 0; i < N; ++i) {
	for (int j = 0; j < N; ++j) {
		printf("%d\t", a[i][j]);
	}
	printf("\n");
}

fun(a, n);
printf("计算后数组:\n");
for (int i = 0; i < N; ++i) {
	for (int j = 0; j < N; ++j) {
		printf("%d\t", a[i][j]);
	}
	printf("\n");
}

}
示例结果:

$ gcc ex008.c -o demo
$ ./demo
原数组为:
1 9 7
3 9 7
2 3 8
计算后数组:
3 9 7
9 27 7
6 9 24
案例ex09: 移动一维数组的内容
1 题目

函数:fun()

功能:移动一维数组的内容

描述:若数组中有n个整数,要求把下标从0到p(含p,p<=n-1)的元素平移到数组的最后
举例:

一维数组:1,2,3,4,5,6,7,8,9,10,p的值为3

移动后:5,6,7,8,9,10,1,2,3,4

2 思路

循环 p 次:

将下标为0的数字进行临时存放,然后将后面的数字平移到前面,最后将临时存放的数字放到最后一位

3 代码

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

/**
函数:fun()
功能:移动一维数组的内容
描述:若数组中有n个整数,要求把下标从0到p(含p,p<=n-1)的元素平移到数组的最后
举例:
一维数组:1,2,3,4,5,6,7,8,9,10,p的值为3
移动后:5,6,7,8,9,10,1,2,3,4
**/

void fun(int *a, int p) {
int temp;
for (int i = 0; i <= p; ++i) {
temp = a[0]; // 临时存放第一个数字
for (int j = 1; j < N; ++j) { // 循环将后续数字进行平移
a[j-1] = a[j];
}
a[N-1] = temp; // 临时数字存放到最后一位
}
}

int main(int argc, char const *argv[]) {
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int p = 3;

printf("原始数组内容:\n");
for (int i = 0; i < N; ++i) {
	printf("%d ", a[i]);
}
printf("\n");

fun(a, p);
printf("平移后数组内容:\n");
for (int i = 0; i < N; ++i) {
	printf("%d ", a[i]);
}
printf("\n");

}
示例结果:

$ gcc ex009.c -o demo
$ ./demo
原始数组内容:
1 2 3 4 5 6 7 8 9 10
平移后数组内容:
5 6 7 8 9 10 1 2 3 4
案例ex10: 删除字符串中所有的空格
1 题目

函数:fun()

功能:删除字符串中所有的空格

举例:

主函数中输入“fds afadsf adf d dsf 67d”

则输出:“fdsafadsfadfddsf67d”

2 思路

设置两指针,begin 和 end

begin 和 end 同时从头开始向后移动:

当遇到空格的时候,end 向后移动,begin不变
当 end 位置不为空格的时候,将 end 位置的字符填充到 begin 的位置
最后,在完成去除空格的操作后,在最后添加 ‘\0’

3 代码

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

/**
函数:fun()
功能:删除字符串中所有的空格
举例:
主函数中输入“fds afadsf adf d dsf 67d”
则输出:“fdsafadsfadfddsf67d”
**/

void fun(char *s) {
int begin = 0, end = 0;
while(s[end]!=’\0’) {
if (s[end] != ’ ') {
s[begin] = s[end];
begin++;
end++;
} else {
end++;
}
}
s[begin] = ‘\0’; // 去除空格后,在最后一位加 ‘\0’
}

int main(int argc, char const *argv[]) {
char s[N] = “fds afadsf adf d dsf 67d”;
printf(“原始字符串:%s\n”, s);
fun(s);
printf(“去空格后字符串:%s\n”, s);
}
示例结果:

$ gcc ex010.c -o demo
$ ./demo
原始字符串:fds afadsf adf d dsf 67d
去空格后字符串:fdsafadsfadfddsf67d
案例ex11: 使用指针实现整数逆序排序
1 题目

函数:fun()

功能:使用指针实现整数逆序排序

描述:在main函数中实现,输入三个数字,使用指针实现三个数字的逆序排序

2 思路

使用指针实现数字的操作

3 代码

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

/**
函数:fun()
功能:使用指针实现整数逆序排序
描述:在main函数中实现,输入三个数字,使用指针实现三个数字的逆序排序
**/

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

void fun(int *p1, int *p2, int *p3) {
if (*p1 < *p2)
swap(p1, p2);
if (*p1 < *p3)
swap(p1, p3);
if (*p2 < *p3)
swap(p2, p3);
}

int main(int argc, char const *argv[]) {
int a, b, c;
int *q1, *q2, *q3;
printf(“请输入三个数字:”);
scanf("%d, %d, %d", &a, &b, &c);
q1 = &a;
q2 = &b;
q3 = &c;

printf("逆序前的数字:%d, %d, %d\n", *q1, *q2, *q3);
fun(q1, q2, q3);
printf("逆序后的数字:%d, %d, %d\n", *q1, *q2, *q3);

}
示例结果:

$ gcc ex011.c -o demo
$ ./demo
请输入三个数字:3,9,1
逆序前的数字:3, 9, 1
逆序后的数字:9, 3, 1

$ ./demo
请输入三个数字:1,2,3
逆序前的数字:1, 2, 3
逆序后的数字:3, 2, 1
案例ex12: 指向结构体变量的指针
1 题目

功能:指向结构体变量的指针

描述:通过结构体指针变量实现显示学生信息

2 思路

熟悉结构体的使用

熟悉指针和结构体的混合使用

3 代码

#include <stdio.h>

/**
功能:指向结构体变量的指针
描述:通过结构体指针变量实现显示学生信息
**/

struct student {
int num;
char name[20];
char sex;
int age;
float score;
};

int main(int argc, char const *argv[]) {
struct student stu = {
1001, “计算广告生态”, ‘M’, 28, 98.5
};
struct student *s = &stu;

printf("No.\t%d\n", s->num);
printf("Name.\t%s\n", s->name);
printf("Sex.\t%c\n", s->sex);
printf("Age.\t%d\n", s->age);
printf("Score.\t%d\n", s->score);

}
示例结果:

$ gcc ex012.c -o demo
$ ./demo
No. 1001
Name. 计算广告生态
Sex. M
Age. 28
Score. 73896
案例ex13: 使用指针输出数组元素
1 题目

目标:熟悉指针和数组的底层逻辑

功能:使用指针输出数组元素

描述:通过指针将数组中你那个各个元素值进行打印输出

2 要点

a. 指向数组的指针实现输出数组元素,定义一个指向数组的指针用来灵活操作数组

int a[10];
int *p;
// 指针 p 指向数组的方法,下面两种都是可以的.
// a 本身就是数组的其实地址,&a[0] 也是数组的起始地址
p = a;
p = &a[0];
b. 指针既是指向变量地址的又是决定指向变量地址的位数的。例如

int p = &a[0];
既是指向数组a的首地址 又是说明了每次指向都int类型的数据,即 4 个字节。

所以,在指定 p 的基类型后,通过指针指向数组,每次 p++ 都是会跳动4个字节,到达下一个位置a[1]。

即:*(p+1) 即取得 a[1] 的数据

3 代码

#include <stdio.h>
#define N 10

/**
目标:熟悉指针和数组的底层逻辑
功能:使用指针输出数组元素
描述:通过指针将数组中你那个各个元素值进行打印输出
**/

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

for (p = a; p < a+10; ++p)	{	// 指针指向进行数组内容打印
	printf("数组中的内容:\n%d\n", *p);
}
return 0;

}
示例结果:

$ gcc ex013.c -o demo
$ ./demo
请输入 10 个数字:
1
2
3
4
5
6
7
8
9
10

数组中的内容:
1
2
3
4
5
6
7
8
9
10
案例ex14: 找出数列中的最大值和最小值
1 题目

函数:max_min()

功能:找出数列中的最大值和最小值

描述:使用指针查找数列中的最大值和最小值(使用指针从而避免使用返回值)

2 思路

使用指针从而避免使用返回值

在主函数中定义最大值 max 和最小值 min,将 max 和 min 的地址传递给函数处理,计算结果直接放到主函数中定义的 max 和 min 的地址中

这样做代码执行高效并且思路清晰

3 代码

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

/**
函数:max_min()
功能:找出数列中的最大值和最小值
描述:使用指针查找数列中的最大值和最小值
**/

void max_min(int *a, int *max, int *min) {
*max = *a; // 将数组下标为 0 的数字初始化给max
*min = *a; // 将数组下标为 0 的数字初始化给min
for (int i = 0; i < N; ++i) {
if(*max < *(a+i)) // 将大于max的值赋值给max
*max = *(a+i);
}

for (int i = 0; i < N; ++i) {
	if(*min > *(a+i))		// 将小于min的值赋值给min
		*min = *(a+i);
}

}

int main(int argc, char const *argv[]) {
int i, a[N];
int max, min;
printf(“请输入 10 个数字:\n”);
for (int i = 0; i < N; ++i) {
scanf("%d", a+i);
// scanf("%d", &a[i]);
}
max_min(a, &max, &min);
printf(“输入的 10 个数字为: “);
for (int i = 0; i < N; ++i) {
printf(”%d “, *(a+i));
}
printf(”\n最大值为:%d\n”, max);
printf("\n最小值为:%d\n", min);
}
示例结果:

$ gcc ex014.c -o demo
$ ./demo
请输入 10 个数字:
3
2
1
10
9
8
7
6
5
4
输入的 10 个数字为: 3 2 1 10 9 8 7 6 5 4
最大值为:10

最小值为:1
案例ex15: 使用指针的指针输出字符串
1 题目

功能:使用指针的指针输出字符串

描述:

使用指针的指针输出字符串。

首先要使用指针数组创建一个字符串数组,然后定义指向指针的指针,使其指向字符串数组,并使用其输出数组的字符串

2 思路

char **p;
这里指向指针的指针,表示指针变量 p 是指向一个指针变量。*p 就表示 p 指向另外一个指针变量,即一个地址。

*p 表示 p 指向指针变量指向的对象的值。 例如: (p+1) 表示 accounts[1] 的内容,指向 accounts[1] 的首地址

3 代码

#include <stdio.h>
#define N 5

/**
函数:fun()
功能:使用指针的指针输出字符串
描述:使用指针的指针输出字符串。
首先要使用指针数组创建一个字符串数组,然后定义指向指针的指针,使其指向字符串数组,并使用其输出数组的字符串
**/

int main(int argc, char const *argv[]) {
char *accounts[] = {
“你好 C语言 1”,
“你好 C语言 2”,
“你好 C语言 3”,
“你好 C语言 4”,
“你好 C语言 5”
}; // 指针数组创建字符串数组

char **p;
p = accounts;													// 注意这里一定是二重指针来指向accounts
for (int i = 0; i < N; ++i) {
	printf("%s\n", *(p+i));							// 使用指针将字符串数组中的字符串打印出来
}

}

示例结果:

$ gcc ex015.c -o demo
yaojianguodeMacBook-Pro:ex100 yaojianguo$ ./demo
欢迎关注公众号, 计算广告生态1
欢迎关注公众号, 计算广告生态2
欢迎关注公众号, 计算广告生态3
欢迎关注公众号, 计算广告生态4
欢迎关注公众号, 计算广告生态5
案例ex16: 使用指向指针的指针对字符串排序
1 题目

函数:sort()

功能:使用指向指针的指针对字符串排序

描述:

使用指向指针的指针对字符串排序,输出是按照字母顺序进行排序

2 思路

a. 熟悉指向指针的指针的使用

char *nums[]={"", “”};
char **p;
p = nums;
熟悉 *p 指向的是 nums[0] 的首地址

b. 引用模块#include <string.h>

使用函数 int strcmp(const char *str1, const char *str2) 进行字符串的比较

该函数返回值如下:

如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
3 代码

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

/**
函数:fun()
功能:使用指向指针的指针对字符串排序
描述:
使用指向指针的指针对字符串排序,输出是按照字母顺序进行排序
**/

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) { // 使用strcmp进行字符串的比较
temp = *(p+i);
*(p+i) = *(p+j);
*(p+j) = temp;
}
}
}
}

int main(int argc, char const *argv[]) {
int n = 5;
char **p;
char *nums[] = {
“one”, “two”, “three”, “four”, “five”, “six”, “seven”, “eight”, “nine”, “ten”
};
p = nums; // 使用指向指针的指针指向字符串数组
printf(“排序前的数组内容为:\n”);
for (int i = 0; i < N; ++i) {
printf("%s “, *(p+i));
}
printf(”\n");

sort(p);
printf("排序后的数组内容为:\n");
for (int i = 0; i < N; ++i) {
	printf("%s ", *(p+i));
}
printf("\n");

}
示例结果:

$ gcc ex016.c -o demo
$ ./demo
排序前的数组内容为:
one two three four five six seven eight nine ten
排序后的数组内容为:
eight five four nine one seven six ten three two
案例ex17: 使用指针连接两个字符串
1 题目

函数:connect()

功能:使用指针连接两个字符串

描述:

实现两个已知字符串的连接,放到另外一个字符串数组中,然后将连接好的字符串进行打印显示

2 思路

使用字符型指针变量和指向字符串的指针做函数的参数来实现字符串的连接

注意初始化 char *conn来存储新字符串的时候,必须先分配存储空间

char *conn = (char *)malloc(strlen(str1)+strlen(str2)+1);
memset(conn, strlen(str1)+strlen(str2)+1, 0); // 可选,初始化填充内存空间
另外,使用指针的特性,使得 conn 不断被赋值, str1 和 str2 指向的存储地址,达到字符串的连接

3 代码

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

/**
函数:connect()
功能:使用指针连接两个字符串
描述:
实现两个已知字符串的连接,放到另外一个字符串数组中,然后将连接好的字符串进行打印显示
**/

void connect(char *str1, char *str2, char *conn) {
while(*str1 != ‘\0’) {
*conn = *str1;
conn++;
str1++;
}
*conn = ‘,’; // 两个字符串直接添加逗号
conn++;
while(*str2 != ‘\0’) {
*conn = *str2;
conn++;
str2++;
}
*conn = ‘\0’;
}

int main(int argc, char const *argv[]) {
char *str1 = “技术分享园子”;
char *str2 = “计算广告生态”;
char *conn = (char *)malloc(strlen(str1)+strlen(str2)+1); // 为 conn 分配空间,否则是无效地址
memset(conn, strlen(str1)+strlen(str2)+1, 0); // 初始化 conn 指向的存储地址
printf(“第一个字符串:%s\n”, str1);
printf(“第二个字符串:%s\n”, str2);
connect(str1, str2, conn);
printf(“连接后的字符串是:\n”);
printf("%s\n", conn);
}
示例结果:

$ gcc ex017.c -o demo
$ ./demo
第一个字符串:技术分享园子
第二个字符串:计算广告生态
连接后的字符串是:
技术分享园子,计算广告生态
案例ex18: 用指针实现逆序存放数组元素的值
1 题目

函数:invert()

功能:用指针实现逆序存放数组元素的值

描述:使用指针将数组中的元素值逆序放置,并且将结果打印出来

2 思路

  1. 程序变量中两个数字进行交换的三种方法

第一种:引入一个中间量

temp=a;
a=b;
b=temp;
第二种:要注意的是a+b可能会超过int的范围,这个是该方法的缺点

a=a+b;
b=a-b;
a=a-b;
第三种:这种方法效率最高,推荐使用

a=a^b;
b=a^b;
a=a^b;
2. 指针的使用

使用指针对数组内容进行操作,数组 a, a 指向数组首位置,a+N-1 指向最后一位。从而利用循环对数组的首尾数字逐个替换

3 代码

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

/**
函数:invert()
功能:用指针实现逆序存放数组元素的值
描述:使用指针将数组中的元素值逆序放置,并且将结果打印出来
**/

void invert(int *a) {
int *begin, *end, mid; // 定义首尾指针
begin = a;
end = a+N-1;
mid = (N-1)/2; // 中间位置
int temp;
for (int i = 0; i <= mid; ++i){ // 循环,首尾指针内容变换
// temp = *begin;
// *begin = *end;
// *end = temp;
*begin = *begin ^ *end;
*end = *begin ^ *end;
*begin = *begin ^ *end;

	++begin;
	--end;
}

}

int main(int argc, char const *argv[]) {
int a[N] = {1,2,3,4,5,6,7,8,9,10};
printf(“当前数组中的值为:”);
for (int i = 0; i < N; ++i) {
printf("%d “, *(a+i));
}
printf(”\n");

invert(a);
printf("使用指针逆序后数组中的值为:");
for (int i = 0; i < N; ++i) {
	printf("%d ", *(a+i));
}
printf("\n");

}
示例结果:

$ gcc ex018.c -o demo
$ ./demo
当前数组中的值为:1 2 3 4 5 6 7 8 9 10
使用指针逆序后数组中的值为:10 9 8 7 6 5 4 3 2 1
案例ex19: 用指针数组构造字符串数组
1 题目

功能:用指针数组构造字符串数组

描述:实现输入一个星期中对应的第几天,可以显示其英文名

目标:熟悉对字符串数组对应的指针的使用

2 思路

要点:通过构造一个字符串数组来指定数组中元素的元素值。

指针数组:即数组中都是指针类型的数据,指针数组中的每个元素都是一个指针

定义:

类型名 *数组名[数组长度];
例如:
char *[5];
其中 p 是一个指针数组,该数组是由 5 个数据元素组成,每个元素相当于一个指针变量,都可以指向一个字符串变量
注意点:*p[4] 与 (*p)[4] 的区别要知道, (*p)[4] 中的 p 是一个指向一维数组的指针变量
3 代码

#include <stdio.h>

/**
功能:用指针数组构造字符串数组
描述:实现输入一个星期中对应的第几天,可以显示其英文名
目标:熟悉对字符串数组对应的指针的使用
**/

int main(int argc, char const *argv[]) {
char *week[] = {
“Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”, “Sunday”
};
int w; // 用来记录周几
printf(“请输入星期几(输入阿拉伯数字):”);
scanf("%d", &w);
printf(“Today is %s.\n”, *(week+w-1));
return 0;
}
示例结果:

$ gcc ex019.c -o demo
$ ./demo
请输入星期几(输入阿拉伯数字):5
Today is Friday
案例ex20: 用指针函数输出学生成绩
1 题目

函数:search()

功能:用指针函数输出学生成绩

描述:指针函数的使用,输入学生的序号,将在窗口输出该序号对应的学生的成绩

2 思路

指向函数的指针变量的形式如下:

数据类型 (*指针变量名)()

例如;

int * search()
*§() 表示定义一个指向函数的指针变量,用来存放函数入口地址。在程序设计过程中,将一个函数地址赋值给它,它就指向那个函数。函数指针变量赋值写法:

p = min;
在赋值的时候,只给出函数名即可,函数名即地址

在使用函数指针调用函数的时候,要写出函数的参数,例如:

m = (*p)(a,b);
3 代码

#include <stdio.h>

/**
函数:search()
功能:用指针函数输出学生成绩
描述:指针函数的使用,输入学生的序号,将在窗口输出该序号对应的学生的成绩
**/

int * search(int (*p)[4], int n) {
int *pt = *(p+n);
return pt;
}

int main(int argc, char const *argv[]) {
int score[][4] = {
{98,56,89,87},
{88,56,87,80},
{92,56,84,82},
{78,56,90,67}
}; // 声明数组,对应四个学生的各科成绩
int no; // 保存学生编号
printf(“输入学生编号:”);
scanf("%d", &no);
int *p = search(score, no);
printf(“学生编号为 %d 的学生成绩为:\n”, no);
for (int i = 0; i < 4; ++i) {
printf("%d\t", *(p+i));
}
putchar(’\n’);
}
示例结果:

$ gcc ex020.c -o demo
$ ./demo
输入学生编号:3
学生编号为3的学生成绩为:
78 56 90 67
案例ex21: 寻找相同元素的指针
1 题目

函数:find()

功能:寻找相同元素的指针

描述:比较两个有序数组的元素,输出两个数组中第一个相同的值

2 思路

利用有序数组有序的特点

建立一个指针函数,这个函数返回值为指针类型,即一个地址。定义如下:

int * find(int *a, int *b, int m, int n);
在程序中调用该函数:

int * p = find(a, b, sizeof(a)/sizeof(a[0]), sizeof(b)/sizeof(b[0]));
返回一个指向整型变量的指针

3 代码

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

/**
函数:find()
功能:寻找相同元素的指针
描述:比较两个有序数组的元素,输出两个数组中第一个相同的值
**/

int * find(int *a, int *b, int m, int n) {
int *pa = a;
int *pb = b;
while(pa < a+m && pb < b+n) {
if (*pa < *pb) {
pa++;
}
else if(*pa > *pb) {
pb++;
}
else {
return pa;
}
}
}

int main(int argc, char const *argv[]) {
int *p;
int a[] = {2,5,7,9,11,34,56}; // 声明两个数组
int b[] = {3,6,8,10,12,34,59}; // 声明两个数组
printf(“两个数组的内容分别是:\n”);
for (int i = 0; i < sizeof(a)/sizeof(a[0]); ++i) { // 打印数组
printf("%d “, *(a+i));
}
printf(”\n");
for (int j = 0; j < sizeof(b)/sizeof(b[0]); ++j) { // 打印数组
printf("%d “, *(b+j));
}
p = find(a, b, sizeof(a)/sizeof(a[0]), sizeof(b)/sizeof(b[0]));
printf(”\n相同的数字是:%d\n", *p);
}
示例结果:

$ gcc ex021.c -o demo
$ ./demo
两个数组的内容分别是:
2 5 7 9 11 34 56
3 6 8 10 12 34 59
相同的数字是:34
案例ex22: 查找成绩不及格的学生
1 题目

函数:search()

功能:查找成绩不及格的学生

描述:有 4 名学生的成绩,找出至少有一科不及格的学生,并将成绩列表输出(规定60以下为不及格)

目标:重点理解 int (*p)[N] 的使用方法

2 思路

int*p[5] 和 int(*p)[5] 的区别

int *p[5],首先它是一个数组,它的大小是5,p里面存放的数据都是类型是int *,也就是整型指针。 所以它叫指针数组。

int (*p)[5],首先p是一个指针,指向大小为5的数组,因此这叫数组指针。通常用在二维数组的操作上

注意指针的类型,从 int(*p)[5] 可以看到, p 的类型不是int , 而是 int()[5],p 被定义为指向一维数组的指针变量,里面有 5 个元素,因此,p 的基类型是一维数组,长度为 20 字节。
*(p+2)+3, 括号中的 2 是指的以 p 的基类型(一维整型数组)的长度为单位的,即,p 每增加 1,地址就增加 20 个字节(5 个元素,每个元素4个字节)。而 *(p+2)+3 括号外的数字 3,不是以 p 的基类型的长度为单位的,而是一维数组的下一个位置
先看一个简单的引例

#include <stdio.h>

void search(float (*p)[4], int n) {
printf(“序号为 %d 的学生的成绩:\n”, n);
for (int i = 0; i < 4; ++i) {
printf("%5.2f ", ((p+n)+i));
}
}

int main(int argc, char const *argv[]) {
float score[3][4]={{60,75,82,91},{75,81,91,90},{51,65,78,84}};
search(score, 2); // 计算得出序号为 2 的学生的成绩
getchar();
}

~操作结果~~
$ gcc ex022-1.c -o demo
./yaojianguodeMacBook-Pro:C语言100题集合代码 yaojianguo$ ./demo
序号为 2 的学生的成绩:
51.00 65.00 78.00 84.00
3 代码

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

/**
函数:search()
功能:查找成绩不及格的学生
描述:有 4 名学生的成绩,找出至少有一科不及格的学生,并将成绩列表输出(规定60以下为不及格)
**/

int * search(int (p)[N]) {
int * pt = (p+1);
for (int i = 0; i < 4; ++i) {
if (
(
(p+0)+i) < 60) { // 这块可以写成*(p+i) < 60,也就是平常看到了(*(p+m)+n))来取到二维数组中列向的值
pt = *p;
}
}
return pt;
}

int main(int argc, char const argv[]) {
int * p;
int score[][N]={{60,75,82,91},{75,81,91,90},{51,65,78,84},{65,72,78,72},{75,70,98,92}}; // 四个学生的成绩
for (int i = 0; i < N; ++i) {
p = search(score+i);
if (p==
(score+i)) {
printf(“成绩不及格学生的成绩分别是:\n”);
for (int j = 0; j < 4; ++j) {
printf("%d ", *(p+j));
}
}
}
getchar();
}
示例结果:

$ gcc ex022.c -o demo
$ ./demo
成绩不及格学生的成绩分别是:
51 65 78 84
案例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 思路

参数传递,使用指针变量
插入数字,找到插入点,从数组的末端逐个向后移动,最后将要插入的数字放到插入点
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 思路

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

找到最大值
创建 int *max(int *a) 函数,指针指向找出的最大值
交换最大值
创建 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) = i3;
}
// 输出
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®); // 调用 ex039_area.h 中的 area函数
}
ex039_area.h:

#define PI 3.14
#define area® PI*®*®
示例结果:

$ 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 思路

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


案例ex45: 将排好序的字符串保存到磁盘文件中
1 题目

功能:将排好序的字符串保存到磁盘文件中

描述:从键盘读入若干个字符串,对它们按字母大小的顺序排序,然后把排好序的字符串送到磁盘文件中保存

2 知识点

2.1 处理字符串的两个函数

函数名	调用形式	功能	返回值
fgets	fgets(str, n, fp)	从fp指向的文件读入一个长度为 (n-1) 的字符串,存放到字符数组str中	读成功,返回地址str,失败则返回 NULL
fputs	fputs(str, fp)	把str所指向的字符串写到文件指针变量 fp 所指向的文件中	输出成功,返回0;否则返回非 0 值
fgets 中最后一个字母 s 表示字符串(string)。fgets 的含义是,从文件读取一个字符串

1. fgets 函数的函数原型

char * fgets(char * str, int n, fILE * fp);
其作用是从文件中读取一个字符串。调用时可以写成

fgets(str, n, fp)
其中 n 是要求得到的字符的个数,但实际上只从fp所指向的文件中读取 n-1 个字符,然后在最后加 '\0' 字符,这样得到的字符串共有 n 个字符,把它们放到数组 str 中。如果在读完 n-1 个字符之前遇到了换行符 '\n' 或者结束符EOF,读入即结束,这块遇到换行符 '\n' 也作为一个字符读入。若执行 fgets函数成功,则返回值为 str 数组元素的地址,如果一开始就遇到文件尾或者读取数据出错,则返回 NULL

2.fputs函数的函数原型

char * fputs(char * str, fILE * fp);
其作用是将str所指向的字符串输出到fp所指向的文件中。调用时可以写成

例如:

fputs("China", fp);
把字符串“China”输出到fp指向的文件中。fputs函数中第 1 个参数可以是字符串常量、字符数组名或者字符型指针。字符串末尾的 '\0' 不输出,若输出成功,函数值为 0;失败时,函数值为 EOF。

fgets 和 fgets 这两个函数的功能类似于 gets 和 puts 函数,只是 gets 和 puts 以终端为读写对象,而 fgets 和 fputs 函数以指定的文件作为读写对象。

3 思路

从键盘读入n个字符串,存放在一个二维字符数组中,每个一维数组存放一个字符串
对字符数组中的n个字符串按字母顺序排序,排好序的字符串仍存放在字符数组中
将字符数组中的字符串顺序输出
4 代码

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

/**
功能:将排好序的字符串保存到磁盘文件中
描述:从键盘读入若干个字符串,对它们按字母大小的顺序排序,然后把排好序的字符串送到磁盘文件中保存
**/

int main(int argc, char const *argv[]) {
	FILE * fp;
	char str[3][20], temp[10];				// str保存存放字符串的二维数组,temp 临时数组
	int i, j, k, n = 3;
	printf("输入三个字符串: \n");				// 提示输入字符串
	for (i = 0; i < n; ++i) {
		gets(str[i]); 										// 终端输入
	}


	for(i=0; i<n-1; i++) {         			// 用选择法对字符串排序
		k=i;
		for(j=i+1;j<n;j++)
			if(strcmp(str[k], str[j]) > 0)
				k=j;
		if(k != i) {
			strcpy(temp, str[i]);
			strcpy(str[i], str[k]);
			strcpy(str[k], temp);
		}
	}

	if ((fp = fopen("save_string.dat", "w")) == NULL) {	 // 打开磁盘文件
		printf("打开文件失败\n");
	}

	printf("新的语句是:\n");
	for (i = 0; i < n; ++i) {
		fputs(str[i], fp);
		fputs("\n", fp);
		printf("%s\n", str[i]);
	}
}
示例结果:

$ gcc ex045.c -o demo
$ ./demo
输入三个字符串:
grasp
apple
banana
新的语句是:
apple
banana
grasp
案例ex46: 用二进制方式向文件读写一组数据
1 题目

函数:save()/read()

功能:用二进制方式向文件读写一组数据

描述:从键盘输入 10 个学生的有关数据,然后把他们转存到磁盘文件中去

2 知识点

在程序中不仅需要一次输入输出一个数据, 而且常常需要一次输入输出一组数据(如数组或结构体变量的值), C语言允许用fread函数从文件中读一个数据块, 用fwrite函数向文件写一个数据块。在读写时是以二进制形式进行的。向磁盘写数据时, 直接将内存中一组数据原封不动、不加转换地复制到磁盘文件上, 在读入时也是将磁盘文件中若干字节的内容一批读入内存
它们的一般调用形式为:

fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);
buffer:是一个地址

对fread来说,它是用来存放从文件读入的数据的存储区的地址

对fwrite来说,是要把此地址开始的存储区中的数据向文件输出(以上指的是起始地址)

size:要读写的字节数

count:要读写多少个数据项(每个数据项长度为size)

fp: FILE类型指针

在打开文件时指定用二进制文件, 这样就可以用 fread 和 fwrite 函数读写任何类型的信息, 例如:

fread(f, 4, 10, fp);
其中 f 是一个 float 型数组名(代表数组首元素地址)。这个函数从 fp 所指向的文件读入10个4字节的数据,存储到数组 f 中。

3 思路

定义一个有 10 个元素的结构体数据,用来存放 10 个学生的数据。

从 main() 中输入 10 个数据。

用 save() 函数实现向磁盘输出学生数据。

用 fwrite() 函数一次输出一个学生的数据

用fread() 函数进行数据的读取

在main函数中,从终端键盘输入io个学生的数据,然后调用 save 函数,将这些数据输出到以“stu.dat”命名的磁盘文件中。fwrite函数的作用是将一个长度为36节的数据块送到 ex046_stud.dat 文件中(一个struct student_type类型结构体变量的长度为它的成员长度之和,即10 + 4 + 4 + 15 = 33,实际上占36字节,是4的倍数)
在fopen函数中指定读写方式为“wb”,即二进制写方式。在向磁盘文件 ex046_stud.dat 写的时候,将内存中存放stud数组元素stud订的内存单元中的内容原样复制到磁盘文件,所建立的 ex046_stud.dat 文件是一个二进制文件。这个文件可以为其他程序所用。
在本程序中,用fopen函数打开文件时没有指定路径,只写了文件名ex046_stud.dat,系统默认其路径为当前用户所使用的子目录,在此目录下建立一个新文件ex046_stud.dat,输出的数据存放在此文件中。
程序运行时,屏幕上并无输出任何信息,只是将从键盘输入的数据送到磁盘文件上
4 代码

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

/**
函数:save()/read()
功能:用二进制方式向文件读写一组数据
描述:从键盘输入 10 个学生的有关数据,然后把他们转存到磁盘文件中去
思路:
**/

struct Student_type {
	char name[10];
	int num;
	int age;
	char addr[30];
}stud[SIZE];

// 以二进制格式进行保存
void save() {
	FILE * fp;
	if ((fp = fopen("ex046_stud.dat", "wb")) == NULL) {		// 打卡输入文件 ex046_stud.dat
		printf("写入文件打开失败!\n");
		return;
	} else {
		printf("写入成功!\n");
	}
	for (int i = 0; i < SIZE; ++i) {
		if(fwrite(&stud[i], sizeof(struct Student_type), 1, fp) != 1)
			printf("写入失败\n");
	}
	fclose(fp);
}

// 从二进制文件中读取数据
void read() {
	FILE * fp;
	if ((fp = fopen("ex046_stud.dat", "rb")) == NULL) {
		printf("读取打开文件失败!\n");
		exit(0);
	}
	for (int i = 0; i < SIZE; ++i) {
		fread(&stud[i], sizeof(struct Student_type), 1, fp); 	// 从 fp 指向的文件读入一组数据
		printf("%s\t%d\t%d\t%s\n", stud[i].name, stud[i].num, stud[i].age, stud[i].addr);
	}
	fclose(fp);
}

int main(int argc, char const *argv[]) {
	printf("输入 %d 个学生的信息:\n", SIZE);
	for (int i = 0; i < SIZE; ++i) {	// 注意 scanf 中的地址传递
		scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age,&stud[i].addr);
	}
	save();
	printf("\n====== 读取写入的数据 =======\n");
	read();
	return 0;
}
示例结果:

$ gcc ex046.c -o demo
$ ./demo
输入 10 个学生的信息:
"A" 1 11 "street01"
"B" 2 12 "street02"
"C" 3 13 "street03"
"D" 4 14 "street04"
"E" 5 15 "street05"
"F" 6 16 "street06"
"G" 7 17 "street07"
"H" 8 18 "street08"
"I" 9 19 "street09"
"J" 10 110 "street010"
写入成功!

====== 读取写入的数据 =======
"A"	1	11	"street01"
"B"	2	12	"street02"
"C"	3	13	"street03"
"D"	4	14	"street04"
"E"	5	15	"street05"
"F"	6	16	"street06"
"G"	7	17	"street07"
"H"	8	18	"street08"
"I"	9	19	"street09"
"J"	10	110	"street010"
亚马逊测评 www.yisuping.cn
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页