浙大版《C语言程序设计》第四版(何钦铭颜晖) 第11章 指针进阶 课后习题答案

你也可以上程序咖(https://meta.chengxuka.com),打开大学幕题板块,不但有答案,讲解,还可以在线答题。

WX20220412-135428@2x

一、选择题

1.下面程序段的运行结果是( )。

int x[5] = {2, 4, 6, 8, 10}, *p, **pp;
p = x;
pp = &p;
printf("%d", *(p++));
printf("%d\n", **pp);

A.4 4

B.2 4

C.2 2

D.4 6

答:B

解析:

题目中先定义了 int 类型的数组 x,又定义两个指针。

然后 p = x,表示将 x 的基地址赋值给 p,所以 p 指向数组中第一个元素。

第一次打印 *(p++),获取 p 指向的元素,打印 2, 然后指针位置向后移动一个位置。

因为 pp = &p,表示将 p 的地址赋值给 pp,所以 pp 指向 p,p 经过上次打印时的 ++,已经向后一定一个,所以第二个打印 **pp,打印的就是 4。

2.对于以下变量定义,正确的赋值是( )。

int *p[3], a[3];

A. p=a

B. *p=a[0]

C. p=&a[0]

D. p[0]=&a[0]

答:D

解析:

定义为int *p[3],a[3]; 可知这里 p 是一个指针数组,p 为数组名,所以不能作为赋值号的左操作数,所以选项 A 和 C 不对 *p 即 p[0],所以选项 B 等效于 p[0]=a[0],a[0]是int类型,而p[0] 应该存储指针变量(int *),所以B也不对。

3.下列程序段的输出是( )。

int i, a[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, *p[4];
for (i = 0; i < 4; i++)
{
	p[i] = &a[i * 3];
}
printf("%d\n", p[3][2]);

A.12

B.8

C.6

D.上述程序有错误

答:A

解析:

题目中定义了一维数组 a[12],以及一个指针数组 p。

当 i=0 时,第一次循环:p[0]=&a[0] ,p[0] 指向 a[0]

当 i=1 时,第二次循环:p[1]=&a[3] ,p[1] 指向 a[3]

当 i=2 时,第三次循环:p[2]=&a[6] ,p[2] 指向 a[6]

当 i=3 时,第四次循环:p[3]=&a[9] ,p[3] 指向 a[9]

当 i=4 时,循环结束。

p[3][2],相当于 p[3]+2,因为 p[3] 指向 a[9] ,所以 p[3][2] 指向 a[11],a[11] 所对应的值是 12 ,所以输出12。

4.设有如下定义的链表,则值为 7 的表达式是( )。

struct st
{
  int n;
  struct st *next;
} a[3] = {5, &a[1], 7, &a[2], 9, NULL}, *p = a;

A. p->n

B. (p->n)++

C. p->next->n

D. ++p->n

答:C

解析:

题目中 *p=a,表示指针 p 指向 a 的基地址。

选项 A,打印数组 a 中第一个元素的 n 的值,输出 5。

选项 B,也是打印 5。因为是后加。

选项 C,p 指向 a 的基地址,默认第一个元素, p->next,表示它的下一个元素,就是 7 和 &a[2],打印它的 n,就是 7。

选项 D,因为 -> 的优先级高于 ++,所以这里取 p -> n,数组中第一个元素的 n ,为 5,前置++,所以打印 6。

5.下面程序段输入一行字符,按输入的逆序建立一个链表。

struct node
	{
		char info;
		struct node *link;

	} * top, *p;
	char c;
	top = NULL;
	while ((c = getchar()) != '\n')
	{
		p = (struct node *)malloc(sizeof(struct node));
		p->info = c;
		___________;
		top = p;
	}

A. top->link=p

B. p->link= top

C. top=p->link

D. p=top->link

答:B

解析:

因为要逆序建立链表,所以让 p->link 赋值为 top,然后 top赋值为 p。

二、填空题

1.下面程序段的输出结果是( )。

const char *s[3] = {"point", "continue", "break"};
	for (int i = 2; i >= 0; i--)
		for (int j = 2; j > i; j--)
			printf("%s\n", s[i] + j);

答:

ntinue

int

oint

解析:

这里是两层循环嵌套,

i=2时,j=2时,内层循环条件不满足。

i=1时,j=2时,打印 s[i]+j ,就是 s[1]+2,对应continue,但是因为要加 2,所以从下标为 2 的字符开始,就是 ntinue。

​ j=1时,内层循环条件不满足。

i=0时,j=2时,打印 s[i]+j ,就是 s[0]+2,对应point,但是因为要加 2,所以从下标为 2 的字符开始,就是 int。

​ j=1时,打印 s[i]+j ,就是 s[0]+1,对应point,但是因为要加 2,所以从下标为 2 的字符开始,就是o int。

2.下面程序段的输出结果是( )。

const char *st[] = {"Hello", "world", "!"}, **p = st;
p++;
printf("%s-%c\n", *p, **p);
(*p)++;
printf("%s-%c-%c\n", *p, **p, (**p) + 1);

答:

world-w

orld-o-p

解析:

首先定义了指针数组 st,存储的是 3 个字符串的地址。然后又定义了二级指针变量 p,这里 p 存储的是 st 的基地址。

然后 p++,那么指向了里面的第二个字符串的地址。*p 打印该字符串。world,**p,打印字符 w。

然后 (*p)++,那么指针向后移动一位,从 o 开始,打印 orld,**p 打印 o, (**p) + 1 先取 **p 就是 o 然后再加 1,就是 p。

3.下面程序段的输出结果是( )。

static int a[4][4];
int *p[4], i, j;
for (i = 0; i < 4; i++)
  p[i] = &a[i][0];
for (i = 0; i < 4; i++)
{
  *(p[i] + i) = 1;
  *(p[i] + 4 - (i + 1)) = 1;
}
for (i = 0; i < 4; i++)
{
  for (j = 0; j < 4; j++)
    printf("%2d", p[i][j]);
  printf("\n");
}

答:

1 0 0 1

0 1 1 0

0 1 1 0

1 0 0 1

解析:

首先定义了一个 4X4 的矩阵,默认都是 0 。

0 0 0 0

0 0 0 0

0 0 0 0

0 0 0 0

然后又定义了一个指针数组 p。

第一个 for 循环中:p[0] 存储 a[0][0] 的地址。p[1] 存储 a[1][0] 的地址。p[2] 存储 a[2][0] 的地址。p[3] 存储 a[3][0] 的地址。

第二个 for 循环中:

i = 0 时,

*(p[i] + i) = 1 ,表示 *(p[0]+0) ,表示 第一行第一个元素修改值为 1。
*(p[i] + 4 - (i + 1)) = 1 ,表示 *(p[0]+3) , 表示第一行第四个元素修改值为 1。

i = 1 时,

*(p[i] + i) = 1 ,表示 *(p[1]+1) ,表示 第二行第二个元素修改值为 1。
*(p[i] + 4 - (i + 1)) = 1 ,表示 *(p[1]+2) , 表示第二行第三个元素修改值为 1。

i = 2 时,

*(p[i] + i) = 1 ,表示 *(p[2]+2) ,表示 第三行第三个元素修改值为 1。
*(p[i] + 4 - (i + 1)) = 1 ,表示 *(p[2]+2) , 表示第三行第二个元素修改值为 1。

i = 3 时,

*(p[i] + i) = 1 ,表示 *(p[3]+3) ,表示 第四行第四个元素修改值为 1。
*(p[i] + 4 - (i + 1)) = 1 ,表示 *(p[3]+0) , 表示第四行第一个元素修改值为 1。

第三个 for 循环,打印这个矩阵,所以最终结果为:

1 0 0 1

0 1 1 0

0 1 1 0

1 0 0 1

4.找出最小字符串。输出多个字符串中最小的字符串。请填空。

	const char *st[] = {"bag", "good", "This", "are", "zoo", "park"};
	const char *smin = _________;
	for (int i = 1; i < 6; i++)
		if (_________ < 0)
			smin = st[i];
	printf("The min string is %s \n",_________ );

答:

*st

strcmp(st[i], smin)

smin

解析:

首先定义了一个字符指针数组,想找到里面的最小字符串,首先取第一个字符串赋值给 smin,所以 *smin = *st,然后循环中依次比较字符串大小,strcmp(st[i], smin) <0 ,那么就取 st[i] 赋给 smin,循环结束后打印 smin 即可。

5.查找最高分。输入 n(n<=10)个成绩,查找最高分并输出。请填空。

#include <stdio.h>
int *GetMax(int score[], int n);
int main(void)
{
	int i, n, score[10], *p;
	scanf("%d", &n);
	for (i = 0; i < n; i++)
		scanf("%d", &score[i]);
	p = _____________;
	printf("Max:%d\n", *p);
	return 0;
}
int *GetMax(int score[], int n)
{
	int i, temp, pos = 0;
	temp = score[0];
	for (i = 0; i < n; i++)
		if (score[i] > temp)
		{
			temp = score[i];
			pos = i;
		}
	return _____________;
}

答:

GetMax(score, n)

score + pos 或者 &score[pos]

解析:

就是定义一个函数,找到数组中的最大值,返回它的地址。所以第一个空调用函数,参数传入数组和 n 的值。第二个空,就是函数中返回结果。数组的本质就是存储数组的基地址,加上 pos 即可。

6.输出链表中不及格学生的学号和成绩。已建立学生"英语"课程的成绩链表(成绩存于 score 域中,学号存于 num 域中),下列函数的功能是输出不及格学生的学号和成绩。请填空。


void require(struct student *head)
{
	struct student *p;
	if (head != NULL)
	{
		____________;
		while (p != NULL)
		{
			if (____________)
				printf("%d%.1f\n", p->num, p->score);
			p = p->next;
		}
	}
}

答:

p = head

p->score < 60

解析:

第一个空将 head 赋值给 p,第二个空判断成绩是否及格。

三、程序设计题

题目1:输出月份英文名:输入月份,输出对应的英文名称。要求用指针数组表示 12 个月的英文名称。例如,输入 5 ,输出 May。试编写相应程序。

答案代码:

#include <stdio.h>

char *getmonth(int n);
int main()
{
	// 习题(11.3.1)
	/*
	输出月份英文名:输入月份,输出对应的英文名称。要求用指针数组表示 12 个月的英文名称。例如,输入 5 ,输出 May。试编写相应程序。
	*/

	char *p;
	int n;
	printf("input n:");
	scanf("%d", &n);
	p = getmonth(n);
	if (p == NULL)
		printf("wrong input!\n");
	else
		printf("%s\n", p);

	return 0;
}

char *getmonth(int n)
{
	int month;
	char *a[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November"};
	if (n > 0 && n < 13)
	{
		switch (n)
		{
		case 1:
			month = 1;
			break;
		case 2:
			month = 2;
			break;
		case 3:
			month = 3;
			break;
		case 4:
			month = 4;
			break;
		case 5:
			month = 5;
			break;
		case 6:
			month = 6;
			break;
		case 7:
			month = 7;
			break;
		case 8:
			month = 8;
			break;
		case 9:
			month = 9;
			break;
		case 10:
			month = 10;
			break;
		case 11:
			month = 11;
			break;
		case 12:
			month = 12;
			break;
		}
		return a[--month];
	}
	else
		return 0;
}

运行结果:

WX20220415-162412@2x

题目2:查找星期:定义一个指针数组,将下表的星期信息组织起来,输入一个字符串,在表中查找,若存在,输出该字符串在表中的序号,否则输出 -1。试编写相应程序。

序号星期
0Sunday
1Monday
2Tuesday
3Wednesday
4Thurday
5Friday
6Saturday

答案代码:

#include <stdio.h>
#include <string.h>
int main()
{
	// 习题(11.3.2)
	/*
	查找星期:定义一个指针数组,将下表的星期信息组织起来,输入一个字符串,在表中查找,若存在,输出该字符串在表中的序号,否则输出 -1。试编写相应程序。
	*/

	char *p[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
	char s[10];
	printf("input string:");
	scanf("%s", s);
	int i = 0, j = -2;
	for (i = 0; i < 7; i++)
	{
		if (!strcmp(p[i], s))
		{
			j = i;
			break;
		}
	}
	printf("%d\n", j);
  return 0;
}

运行结果:

WX20220415-163013@2x

题目3:计算最长的字符串长度:输入 n(n<10)个字符串,输出其中最长字符串的有效长度。要求自定义函数 int max_ len(char *s[], int n),用于计算有 n 个无素的指针数组 s 中最长的字符串的长度。试编写相应程序。

答案代码:

#include <stdio.h>
#include <string.h>
int max_len(char *s[], int n);
int main()
{
	// 习题(11.3.3)
	/*
	计算最长的字符串长度:输入 n(n<10)个字符串,输出其中最长字符串的有效长度。要求自定义函数 int max_ len(char *s[ ],int n),用于计算有 n 个无素的指针数组 s 中最长的字符串的长度。试编写相应程序。
	*/

	int i, n;
	char *s[10];
	char a[10][10];
	printf("input n(n<10):");
	scanf("%d", &n);
	printf("input %d  string :\n", n);
	for (i = 0; i < n; i++)
	{
		scanf("%s", a[i]);
		s[i] = a[i];
	}
	printf("%d\n", max_len(s, n));
	return 0;
}

int max_len(char *s[], int n)
{
	int i, j = 0;
	for (i = 0; i < n; i++)
	{
		if (strlen(s[i]) > strlen(s[j]))
		{
			j = i;
		}
	}
	return strlen(s[j]);
}

运行结果:

WX20220415-163731@2x

题目4:字符串的连接:输入两个字符串,输出连接后的字符串。要求自定义函数 char *streat(char *s, char *t), 将字符串 t 复制到字符串 s 的末端,并且返回字符串 s 的首地址。试编写相应程序。

答案代码:

#include <stdio.h>

char *streat(char *s, char *t);
int main()
{
	// 习题(11.3.4)
	/*
	字符串的连接:输入两个字符串,输出连接后的字符串。要求自定义函数 char *streat(char *s, char *t), 将字符串 t 复制到字符串 s 的末端,并且返回字符串 s 的首地址。
	*/

	char s[80], t[80];
	printf("input 1 string s:");
	gets(s);
	printf("input 2 string t:");
	gets(t);

	printf("%s\n", streat(s, t));
	return 0;
}

char *streat(char *s, char *t)
{
	int i = 0;
	int j = 0;
	while (s[i] != '\0')
	{
		i++;
	}
	while (t[j] != '\0')
	{
		s[i] = t[j];
		i++;
		j++;
	}
	return s;
}

运行结果:

WX20220415-164706@2x

题目5:指定位置输出字符串:输入一个字符串后再输入两个字符,输出此字符串中从与第 1 个字符匹配的位置开始到与第 2 个字符匹配的位置结束的所有字符。例如,输入字符串 “program” 与 2 个字符 “r” 和 “g” 后,输出 “rog” 。要求自定义函数 char *match(char *s, char ch1, char ch2) 返回结果字符串的首地址。试编写相应程序。

答案代码:

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

char *match(char *s, char ch1, char ch2);
int main()
{
	// 习题(11.3.5)
	/*
	指定位置输出字符串:输入一个字符串后再输入两个字符,输出此字符串中从与第 1 个字符匹配的位置开始到与第 2 个字符匹配的位置结束的所有字符。例如,输入字符串 "program" 与 2 个字符 "r" 和 "g" 后,输出 "rog" 。要求自定义函数 char *match(char *s, char ch1, char ch2)返回结果字符串的首地址。
	*/

	char s[100], *p;
	char ch1, ch2;
	printf("input string:");
	scanf("%s", s);
	getchar();
	printf("input two char:");
	scanf("%c %c", &ch1, &ch2);
	p = match(s, ch1, ch2);
	if (p != NULL)
		printf("%s\n", p);
	else
		printf("Not found!\n");
	return 0;
}

char *match(char *s, char ch1, char ch2)
{
	char c[100], *p;
	int i = 0;
	int j = 0;
	int start = -1;
	int end = -1;
	int k;
	while (s[i] != '\0')
	{
		if (s[i] == ch1) // 找到起始下标
		{
			start = i;
		}
		if (s[i] == ch2) //找到结束下标
		{
			end = i;
			break; // 如果找到了,就可以直接结束while循环了。
		}
		i++;
	}
	if (start >= 0 && start <= end)
	{
		// 遍历 start到 end的字符
		k = start;
		while (k <= end)
		{
			c[j] = s[k];
			k++;
			j++;
		}
		c[j] = '\0';
		p = c;
		return p;
	}
	else
	{
		return NULL;
	}
}

运行结果:

WX20220415-173000@2x

题目6:查找子串:输入两个字符串 s 和 t ,在字符串 s 中查找子串 t ,输出起始位置,若不存在,则输出 -1。要求自定义函数 char *search(char *s, char *t)返回子串 t 的首地址,若未找到,则返回 NULL 。试编写相应程序。

答案代码:

#include <stdio.h>
#include <string.h>
char *search(char *s, char *t);
int main()
{
	// 习题(11.3.6)
	/*
	查找子串:输入两个字符串 s 和 t ,在字符串 s 中查找子串 t ,输出起始位置,若不存在,则输出 -1。要求自定义函数 char *search(char *s, char *t)返回子串 t 的首地址,若未找到,则返回 NULL 。
	*/

	char s[100], t[100], *p;
	printf("input  string:");
	scanf("%s", s);
	printf("input substring:");
	scanf("%s", t);

	p = search(s, t);
	if (p != NULL)
	{
		printf("%ld\n", p - s);
	}
	else
	{
		printf("-1\n");
	}
	return 0;
}
char *search(char *s, char *t)
{
	int size_t = strlen(t), size_s = strlen(s), T, i, j;
	char *p = NULL;
	for (i = 0; i <= (size_s - size_t); i++)
	{
		p = s + i;
		T = 1;
		for (j = 0; j < size_t; j++)
		{
			if (*p != *(t + j))
			{
				T = 0;
				break;
			}
			p++;
		}
		if (T == 1)
			break;
	}
	if (T == 0)
		return NULL;
	else
		return s + i;
}

运行结果:

WX20220415-180451@2x

题目7:奇数值结点链表:输入若干个正整数(输入 -1 为结束标志)建立一个单向链表,头指针为 L ,将链表 L 中奇数值的结点重新组成个新的链表 NEW ,并输出新建链表的信息。试编写相应程序。

答案代码:

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

struct ListNode
{
	int data;
	struct ListNode *next;
};

struct ListNode *readlist();
struct ListNode *getodd(struct ListNode **L);
void printlist(struct ListNode *L);
int main()
{
	// 习题(11.3.7)
	/*
	奇数值结点链表:输入若干个正整数(输入 -1 为结束标志)建立一个单向链表,头指针为 L ,将链表 L 中奇数值的结点重新组成个新的链表 NEW ,并输出新建链表的信息。
	*/

	struct ListNode *L, *Odd;
	L = readlist();
	Odd = getodd(&L);
	printlist(Odd);
	printlist(L);
	return 0;
}

void printlist(struct ListNode *L)
{
	struct ListNode *p = L;
	while (p)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

struct ListNode *readlist()
{
	int data;							// 输入数据
	int size = sizeof(struct ListNode); // 单个链表结点占据的内存
	struct ListNode *head, *tail, *p;
	head = tail = NULL;
	printf("input number:");
	scanf("%d", &data);
	while (data != -1)
	{
		p = (struct ListNode *)malloc(size);
		p->data = data;
		p->next = NULL;
		if (head == NULL)
		{
			head = p;
		}
		else
		{
			tail->next = p;
		}
		tail = p;
		scanf("%d", &data);
	}

	return head;
}

struct ListNode *getodd(struct ListNode **L)
{
	int data;
	int size = sizeof(struct ListNode);
	struct ListNode *head, *tail, *pNew; // 链表New
	struct ListNode *ptr1, *ptr2;
	head = tail = NULL;

	// L链表的head是奇数
	while (*L != NULL && (*L)->data % 2 != 0)
	{
		data = (*L)->data;
		// 将L链表的奇数重新组成一个新的链表
		pNew = (struct ListNode *)malloc(size);
		pNew->data = data;
		pNew->next = NULL;
		if (head == NULL)
		{
			head = pNew;
		}
		else
		{
			tail->next = pNew;
		}
		tail = pNew;

		// 删除L链表的奇数
		ptr2 = *L;
		*L = (*L)->next;
		free(ptr2);
	}

	if (*L == NULL)
	{
		return NULL;
	}

	// L链表的head非奇数
	ptr1 = *L;
	ptr2 = (*L)->next;
	while (ptr2 != NULL)
	{
		data = ptr2->data;
		if (data % 2 != 0)
		{
			// 将L链表的奇数重新组成一个新的链表
			pNew = (struct ListNode *)malloc(size);
			pNew->data = data;
			pNew->next = NULL;
			if (head == NULL)
			{
				head = pNew;
			}
			else
			{
				tail->next = pNew;
			}
			tail = pNew;

			// 删除L链表的奇数
			ptr1->next = ptr2->next;
			free(ptr2);
		}
		else
		{
			ptr1 = ptr2;
		}
		ptr2 = ptr1->next;
	}

	return head;
}

运行结果:

WX20220415-181818@2x

题目8:删除结点:输入若干个正整数(输入 -1 为结束标志)建立一个单向链表,再输入一个整数 m ,删除链表中值为 m 的所有结点。试编写相应程序。

答案代码:

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

struct ListNode
{
	int data;
	struct ListNode *next;
};

struct ListNode *readlist();
struct ListNode *deletem(struct ListNode *L, int m);
void printlist(struct ListNode *L);
int main()
{
	// 习题(11.3.8)
	/*
	删除结点:输入若干个正整数(输入 -1 为结束标志)建立一个单向链表,再输入一个整数 m ,删除链表中值为 m 的所有结点。
	*/

	int m;
	struct ListNode *L = readlist();
	printf("input m:");
	scanf("%d", &m);
	L = deletem(L, m);
	printlist(L);
	return 0;
}

void printlist(struct ListNode *L)
{
	struct ListNode *p = L;
	while (p)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

struct ListNode *readlist()
{
	int data;
	int size = sizeof(struct ListNode);
	struct ListNode *head, *tail, *p;
	head = tail = NULL;
	printf("input number:");
	scanf("%d", &data);
	while (data != -1)
	{
		p = (struct ListNode *)malloc(size);
		p->data = data;
		p->next = NULL;
		if (head == NULL)
		{
			head = p;
		}
		else
		{
			tail->next = p;
		}
		tail = p;

		scanf("%d", &data);
	}

	return head;
}

struct ListNode *deletem(struct ListNode *L, int m)
{
	struct ListNode *ptr1, *ptr2;

	//要被删除结点为表头结点
	while (L != NULL && L->data == m)
	{
		ptr2 = L;
		L = L->next;
		free(ptr2);
	}

	// 链表空
	if (L == NULL)
	{
		return NULL;
	}

	// 要被删除结点为非表头结点
	ptr1 = L;
	ptr2 = L->next; // 从表头的下一个结点搜索所有符合删除要求的结点
	while (ptr2 != NULL)
	{
		if (ptr2->data == m) // ptr2所指结点符合删除要求
		{
			ptr1->next = ptr2->next;
			free(ptr2);
		}
		else
		{
			ptr1 = ptr2; // ptr1后移一个结点
		}
		ptr2 = ptr1->next; // ptr2指向ptr1的后一个结点
	}

	return L;
}

运行结果:

WX20220415-182157@2x

  • 12
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值