《C語(yǔ)言程序設(shè)計(jì)》(譚浩強(qiáng)第五版) 第8章 善于利用指針 習(xí)題解析與答案

你也可以上程序咖(https://meta.chengxuka.com)试伙,打開(kāi)大學(xué)幕題板塊析校,不但有答案,講解滥比,還可以在線(xiàn)答題牙咏。

WX20220412-135428@2x.png

本章習(xí)題均要求用指針?lè)椒ㄌ幚怼?/p>

題目1:輸入3個(gè)整數(shù)臼隔,按由小到大的順序輸出。

解:

答案代碼:

#include <stdio.h>
int main()
{

    void swap(int *p1, int *p2);
    int n1, n2, n3;
    int *p1, *p2, *p3;
    printf("input three integer n1,n2,n3:");
    scanf("%d,%d,%d", &n1, &n2, &n3);
    p1 = &n1;
    p2 = &n2;
    p3 = &n3;
    if (n1 > n2)
        swap(p1, p2);
    if (n1 > n3)
        swap(p1, p3);
    if (n2 > n3)
        swap(p2, p3);
    printf("Now,the order is:%d,%d,%d\n", n1, n2, n3);
    return 0;
}
void swap(int *p1, int *p2)
{
    int p;
    p = *p1;
    *p1 = *p2;
    *p2 = p;
}

運(yùn)行結(jié)果:

WX20220328-141944@2x.png

題目2:輸入3個(gè)字符串妄壶,按由小到大的順序輸出摔握。

解:

#include <stdio.h>
#include <string.h>
int main()
{
    void swap(char *, char *);
    char str1[20], str2[31], str3[20];
    printf("input three line:\n");
    gets(str1);
    gets(str2);
    gets(str3);
    if (strcmp(str1, str2) > 0)
        swap(str1, str2);
    if (strcmp(str1, str3) > 0)
        swap(str1, str3);
    if (strcmp(str2, str3) > 0)
        swap(str2, str3);
    printf("Now,the order is:\n");
    printf("%s\n%s\n%s\n", str1, str2, str3);
    return 0;
}

void swap(char *p1, char *p2)
{
    char p[20];
    strcpy(p, p1);
    strcpy(p1, p2);
    strcpy(p2, p);
}

運(yùn)行結(jié)果:

WX20220328-145323@2x.png

輸入3行文字,程序把它們按字母由小到大的順序輸出丁寄。

題目3:輸入10個(gè)整數(shù)氨淌,將其中最小的數(shù)與第一個(gè)數(shù)對(duì)換,把最大的數(shù)與最后一個(gè)數(shù)對(duì)換伊磺。寫(xiě)3 個(gè)函數(shù):

①輸入 10個(gè)數(shù);

②進(jìn)行處理;

③輸出 10 個(gè)數(shù)盛正。

解:

#include <stdio.h>
int main()
{
    void input(int *);
    void max_min_value(int *);
    void output(int *);
    int number[10];
    input(number);         //調(diào)用輸入10 個(gè)數(shù)的函數(shù)
    max_min_value(number); //調(diào)用交換函數(shù)
    output(number);        //調(diào)用輸出函數(shù)
    return 0;
}

//輸入10 個(gè)數(shù)的函數(shù)
void input(int *number)
{
    int i;
    printf("input 10 numbers:");
    for (i = 0; i < 10; i++)
        scanf("%d", &number[i]);
}

// 交換函數(shù)
void max_min_value(int *number)
{
    int *max, *min, *p, temp;
    max = min = number; //開(kāi)始時(shí)使 max和 min都指向第1個(gè)數(shù)
    for (p = number + 1; p < number + 10; p++)
        if (*p > *max)
            max = p; //若 p指向的數(shù)大于max指向的數(shù),就使 max指向p指向的大數(shù)
        else if (*p < *min)
            min = p;  //若 p指向的數(shù)小于min指向的數(shù)屑埋,就使 min指向p指向的小數(shù)
    temp = number[0]; //將最小數(shù)與第1個(gè)數(shù) number[0]交換
    number[0] = *min;
    *min = temp;
    if (max == number)
        max = min;    //如果 max和 number相等豪筝,表示第1個(gè)數(shù)是最大數(shù),則使 max指向當(dāng)前的最大數(shù)
    temp = number[9]; //將最大數(shù)與最后一個(gè)數(shù)交換
    number[9] = *max;
    *max = temp;
}

//輸出函數(shù)
void output(int *number)
{
    int *p;
    printf("Now, they are:   ");
    for (p = number; p < number + 10; p++)
        printf("%d ", *p);
    printf("\n");
}

分析:關(guān)鍵在 max_min_value 函數(shù)摘能,請(qǐng)認(rèn)真分析此函數(shù)续崖。形參 number 是指針,局部變量 max团搞,min和 p都定義為指針變量严望,max 用來(lái)指向當(dāng)前最大的數(shù),min 用來(lái)指向當(dāng)前最小的數(shù)逻恐。

number 是第 1 個(gè)數(shù) number[0] 的地址像吻,開(kāi)始時(shí)執(zhí)行 max=min=number 的作用就是使 max 和 min 都指向第 1 個(gè)數(shù) number[0] 。以后使 p 先后指向10個(gè)數(shù)中的第 2~10 個(gè)數(shù)复隆。如果發(fā)現(xiàn)第 2 個(gè)數(shù)比第 1 個(gè)數(shù) number[0] 大拨匆,就使 max 指向這個(gè)大的數(shù),而 min 仍指向第 1 個(gè)數(shù)昏名。如果第 2 個(gè)數(shù)比第. 1個(gè)數(shù) number[0] 小涮雷,就使 min 指向這個(gè)小的數(shù),而 max 仍指向第 1個(gè)數(shù)。然后使 p 移動(dòng)到指向第 3 個(gè)數(shù),處理方法同前堂鲤。直到 p 指向第 10 個(gè)數(shù)碑诉,并比較完畢為止。此時(shí) max. 指向 10個(gè)數(shù)中的最大者,min 指向 10 個(gè)數(shù)中的最小者。假如原來(lái) 10 個(gè)數(shù)是:

32      24      56      78      1       98      36      44      29      6

在經(jīng)過(guò)比較和對(duì)換后,max和 min的指向?yàn)?/p>

32      24      56      78      1       98      36      44      29      6
                                                ↑       ↑
                                                min max

此時(shí)蜓竹,將最小數(shù) 1 與第 1 個(gè)數(shù)(即 number[0] )32 交換,將最大數(shù) 98 與最后一個(gè)數(shù) 6 交換。因此應(yīng)執(zhí)行以下兩行:

temp = number[0]; number[0] = *min;*min = temp;//將最小數(shù)與第1個(gè)數(shù) number[0]交換
    
temp = number[9]; number[9] = *max;*max = temp;//將最大數(shù)與最后一個(gè)數(shù)交換

最后將已改變的數(shù)組輸出俱济。

運(yùn)行結(jié)果:

WX20220328-151021@2x.png

但是嘶是,有一個(gè)特殊的情況應(yīng)當(dāng)考慮:如果原來(lái) 10 個(gè)數(shù)中第 1 個(gè)數(shù) number[0] 最大,如:

98      24      56      78      1       32      36      44      29      6

在經(jīng)過(guò)比較和對(duì)換后蛛碌,max 和 min 的指向?yàn)?/p>

98      24      56      78      1       32      36      44      29      6
↑                                               ↑       
max                                         min 

在執(zhí)行完上面第1行"temp=number[0] ;number[0]=*min;*min=temp;"后聂喇,最小數(shù) 1 與第 1個(gè)數(shù) number[0] 對(duì)換,這個(gè)最大數(shù)就被調(diào)到后面去了(與最小的數(shù)對(duì)調(diào))蔚携。

1       24      56      78      98      32      36      44      29      6
↑                                           ↑       
max                                     min 

請(qǐng)注意:數(shù)組元素的值改變了希太,但是 max 和 min 的指向未變,max 仍指向 number[0]酝蜒。此時(shí)如果接著執(zhí)行下一行:temp= number[9];number[9]=* max;* max= temp; 就會(huì)出問(wèn)題誊辉,因?yàn)榇藭r(shí) max 并不指向最大數(shù),而指向的是第1個(gè)數(shù)亡脑,結(jié)果是將第 1個(gè)數(shù)(最小的數(shù)已調(diào)到此處)與最后一個(gè)數(shù) number[9] 對(duì)調(diào)堕澄。結(jié)果變成:

6       24      56      78      98      32      36      44      29      1

顯然就不對(duì)了。

為此远豺,在以上兩行中間加上一行:

if(max== number)max = min;

由于經(jīng)過(guò)執(zhí)行"temp= number[0]; number[0]=* min;* min=temp;"后奈偏,10 個(gè)數(shù)的排列為

1       24      56      78      98      32      36      44      29      6
↑                                           ↑       
max                                     min 

max指向第 1 個(gè)數(shù),if 語(yǔ)句判別出 max 和 number 相等(即 max 和 number 都指向 number[0] )躯护,而實(shí)際上 max 此時(shí)指向的已非最大數(shù)了,就執(zhí)行"max=min"丽涩,使 max 也指向 min 當(dāng)前的指向棺滞。而 min 原來(lái)是指向最小數(shù)的,剛才與 number[0] 交換矢渊,而 number[0] 原來(lái)是最大數(shù)继准,所以現(xiàn)在 min 指向的是最大數(shù)。執(zhí)行 max=min 后 max也指向這個(gè)最大數(shù)矮男。

1       24      56      78      98      32      36      44      29      6
                                            ↑       
                                        max,min 

然后執(zhí)行下面的語(yǔ)句:

temp = number[9]; number[9]=*max;* max= temp;

這就沒(méi)問(wèn)題了移必,實(shí)現(xiàn)了把最大數(shù)與最后一個(gè)數(shù)交換。

運(yùn)行結(jié)果:

WX20220328-154006@2x.png

讀者可以將上面的"if(max==number)max=min;" 刪去毡鉴,再運(yùn)行程序崔泵,輸入以上數(shù)據(jù),分析一下結(jié)果猪瞬。

也可以采用另一種方法:先找出 10 個(gè)數(shù)中的最小數(shù)憎瘸,把它和第 1 個(gè)數(shù)交換,然后再重新找 10 個(gè)數(shù)中的最大數(shù)陈瘦,把它和最后一個(gè)數(shù)交換幌甘。這樣就可以避免出現(xiàn)以上的問(wèn)題。重寫(xiě)void max_min_value 函數(shù)如下:

//交換函數(shù)
void max_min_value(int *number)
{
    int *max, *min, *p, temp;
    max = min = number; //開(kāi)始時(shí)使max和min都指向第1個(gè)數(shù)
    for (p = number + 1; p < number + 10; p++)
        if (*p < *min) //若p指向的數(shù)小于min指向的數(shù),就使min指向p指向的小數(shù)
            min = p;
    temp = number[0]; //將最小數(shù)與第1個(gè)數(shù) number[0] 交換
    number[0] = *min;
    *min = temp;
    for (p = number + 1; p < number + 10; p++)
        if (*p > *max) //若p指向的數(shù)大于max指向的數(shù)锅风,就使max指向p指向的大數(shù)
            max = p;
    temp = number[9]; //將最大數(shù)與最后一個(gè)數(shù)交換
    number[9] = *max;
    *max = temp;
}

這種思路容易理解酥诽。

這道題有些技巧,請(qǐng)讀者仔細(xì)分析皱埠,學(xué)會(huì)分析程序運(yùn)行時(shí)出現(xiàn)的各種情況肮帐,并善于根據(jù)情況予以妥善處理。

題目4:有n個(gè)整數(shù)漱逸,使前面各數(shù)順序向后移 m 個(gè)位置泪姨,最后 m 個(gè)數(shù)變成最前面 m 個(gè)數(shù),見(jiàn)圖 8.43饰抒。寫(xiě)一函數(shù)實(shí)現(xiàn)以上功能肮砾,謎在主函數(shù)中輸入 n個(gè)整數(shù)和輸出調(diào)整后的n個(gè)數(shù)。

WX20220328-113140@2x.png

解:

答案代碼:

#include <stdio.h>
int main()
{
    void move(int[20], int, int);
    int number[20], n, m, i;
    printf("how many numbers?"); //問(wèn)共有多少個(gè)數(shù)
    scanf("%d", &n);
    printf("input %d numbers:\n", n);
    for (i = 0; i < n; i++)
        scanf("%d", &number[i]);             //輸入n 個(gè)數(shù)
    printf("how many place you want move?"); //問(wèn)后移多少個(gè)位置
    scanf("%d", &m);
    move(number, n, m); //調(diào)用move 函數(shù)
    printf("Now,they are:\n");
    for (i = 0; i < n; i++)
        printf("%d ", number[i]);
    printf("\n");
    return 0;
}

//循環(huán)后移一次的函數(shù)
void move(int array[20], int n, int m)
{
    int *p, array_end;
    array_end = *(array + n - 1);
    for (p = array + n - 1; p > array; p--)
        *p = *(p - 1);
    *array = array_end;
    m--;
    if (m > 0) //遞歸調(diào)用袋坑,當(dāng)循環(huán)次數(shù)m減至為0時(shí)仗处,停止調(diào)用
        move(array, n, m);
}

運(yùn)行結(jié)果:

WX20220328-155243@2x.png

題目5:有 n 個(gè)人圍成一圈,順序排號(hào)枣宫。從第 1 個(gè)人開(kāi)始報(bào)數(shù)婆誓。(從1到3報(bào)數(shù)),凡報(bào)到3 的 人退出圈子也颤,問(wèn)最后留下的是原來(lái)第幾號(hào)的那位洋幻。

解:N-S圖如圖8.2所示。

WX20220328-155351@2x.png

答案代碼:

#include <stdio.h>
int main()
{
    int i, k, m, n, num[50], *p;
    printf("\ninput number of person: n=");
    scanf("%d", &n);
    p = num;
    for (i = 0; i < n; i++)
        *(p + i) = i + 1; //以1至 n 為序給每個(gè)人編號(hào)
    i = 0;                // i為每次循環(huán)時(shí)計(jì)數(shù)變量
    k = 0;                // k 為按1翅娶,2文留,3報(bào)數(shù)時(shí)的計(jì)數(shù)變量
    m = 0;                // m為退出人數(shù)
    while (m < n - 1)     //當(dāng)退出人數(shù)比 n-1少時(shí)(即未退出人數(shù)大于1時(shí))執(zhí)行循環(huán)體
    {
        if (*(p + i) != 0)
            k++;
        if (k == 3)
        {
            *(p + i) = 0; //對(duì)退出的人的編號(hào)置為0
            k = 0;
            m++;
        }
        i++;
        if (i == n) //報(bào)數(shù)到尾后,i 恢復(fù)為0了
            i = 0;
    }
    while (*p == 0)
        p++;
    printf("The last one is NO.%d\n", *p);
    return 0;
}

運(yùn)行結(jié)果:

WX20220328-160127@2x.png

題目6:寫(xiě)一函數(shù)竭沫,求一個(gè)字符串的長(zhǎng)度燥翅。在 main 函數(shù)中輸入字符串,并輸出其長(zhǎng)度蜕提。

解:

答案代碼:

#include <stdio.h>
int main()
{
    int length(char *p);
    int len;
    char str[20];
    printf("input string: ");
    scanf("%s", str);
    len = length(str);
    printf("The length of string is %d.\n", len);
    return 0;
}

//求字符串長(zhǎng)度函數(shù)
int length(char *p)
{
    int n;
    n = 0;
    while (*p != '\0')
    {
        n++;
        p++;
    }
    return (n);
}

運(yùn)行結(jié)果:

WX20220328-160603@2x.png

題目7:有一字符串森书,包含 n 個(gè)字符。寫(xiě)一函數(shù)谎势,將此字符串中從第 m 個(gè)字符開(kāi)始的全部字符復(fù)制成為另一個(gè)字符串凛膏。

解:

答案代碼:

#include <stdio.h>
#include <string.h>
int main()
{
    void copystr(char *, char *, int);
    int m;
    char str1[20], str2[20];
    printf("input string:");
    gets(str1);
    printf("which character that begin to copy?");
    scanf("%d", &m);
    if (strlen(str1) < m)
        printf("input error!");
    else
    {
        copystr(str1, str2, m);
        printf("result:%s\n", str2);
    }
    return 0;
}

void copystr(char *p1, char *p2, int m) //字符串部分復(fù)制函數(shù)
{
    int n;
    n = 0;
    while (n < m - 1)
    {
        n++;
        p1++;
    }
    while (*p1 != '\0')
    {
        *p2 = *p1;
        p1++;
        p2++;
    }
    *p2 = '\0';
}

運(yùn)行結(jié)果:

WX20220328-161203@2x.png

題目8:輸入一行文字,找出其中大寫(xiě)字母它浅、小寫(xiě)字母译柏、空格、數(shù)字以及其他字符各有多少姐霍。

解:

答案代碼:

#include <stdio.h>
int main()
{

    int upper = 0, lower = 0, digit = 0, space = 0, other = 0, i = 0;
    char *p, s[20];
    printf("input string:   ");
    while ((s[i] = getchar()) != '\n')
        i++;
    p = &s[0];
    while (*p != '\n')
    {
        if (('A' <= *p) && (*p <= 'Z'))
            ++upper;
        else if (('a' <= *p) && (*p <= 'z'))
            ++lower;
        else if (*p == ' ')
            ++space;
        else if ((*p <= '9') && (*p >= '0'))
            ++digit;
        else
            ++other;
        p++;
    }
    printf("upper case:%d   lower case:%d", upper, lower);
    printf("    space:%d    digit:%d    other:%d\n", space, digit, other);
    return 0;
}

運(yùn)行結(jié)果:

WX20220328-162119@2x.png

題目9:寫(xiě)一函數(shù)鄙麦,將一個(gè) 3×3 的整型矩陣轉(zhuǎn)置典唇。

解:

答案代碼:

#include <stdio.h>
int main()
{
    void move(int *pointer);
    int a[3][3], *p, i;
    printf("input matrix:\n");
    for (i = 0; i < 3; i++)
        scanf("%d %d %d", &a[i][0], &a[i][1], &a[i][2]);
    p = &a[0][0];
    move(p);
    printf("Now,matrix:\n");
    for (i = 0; i < 3; i++)
        printf("%d %d %d\n", a[i][0], a[i][1], a[i][2]);
    return 0;
}
void move(int *pointer)
{
    int i, j, t;
    for (i = 0; i < 3; i++)
        for (j = i; j < 3; j++)
        {
            t = *(pointer + 3 * i + j);
            *(pointer + 3 * i + j) = *(pointer + 3 * j + i);
            *(pointer + 3 * j + i) = t;
        }
}

運(yùn)行結(jié)果:

WX20220328-162908@2x.png

說(shuō)明: a 是二維數(shù)組,p 和形參 pointer 是指向整型數(shù)據(jù)的指針變量胯府,p 指向數(shù)組 0 行 0 列元素 a[0][0] 介衔。在調(diào)用 move 函數(shù)時(shí),將實(shí)參p的值&a[0][0] 傳遞給形參 pointer骂因,在 move 函數(shù)中將 a[i][j]a[j][i] 的值互換炎咖。由于 a 數(shù)組的大小是 3×3,而數(shù)組元素是按行排列的寒波,因此 a[i][j] 在 a 數(shù)組中是第(3×i+j)個(gè)元素乘盼,例如,a[2][1]是數(shù)組中第(3×2+1)個(gè)元素俄烁,即第 7 個(gè)元素(序號(hào)從 0 算起)绸栅。a[i][j]的地址是(pointer十3*i+j,同理页屠,a[i][j] 的地址是(pointer十3*j+i)粹胯。將*(pointer+3*i+j)*(pointer+3*j+i)互換,就是將a[i][j]a[j][i]互換辰企。

題目10:將一個(gè) 5×5 的矩陣中最大的元素放在中心风纠,4 個(gè)角分別放 4 個(gè)最小的元素(順序?yàn)閺淖蟮接遥瑥纳系较乱来螐男〉酱蟠娣牛├蚊常瑢?xiě)一函數(shù)實(shí)現(xiàn)之竹观。用 main 函數(shù)調(diào)用。

解:

答案代碼(1):

#include <stdio.h>
int main()
{
    void change(int *p);
    int a[5][5], *p, i, j;
    printf("input matrix:\n"); //提示輸入二維數(shù)組各元素
    for (i = 0; i < 5; i++)
        for (j = 0; j < 5; j++)
            scanf("%d", &a[i][j]);
    p = &a[0][0]; //使p指向0行0列元素
    change(p);    //調(diào)用change 函數(shù)潜索,實(shí)現(xiàn)交換
    printf("Now,matrix:\n");
    for (i = 0; i < 5; i++) //輸出已交換的二維數(shù)組
    {
        for (j = 0; j < 5; j++)
            printf("%d ", a[i][j]);
        printf("\n");
    }
    return 0;
}

//交換函數(shù)
void change(int *p)
{
    int i, j, temp;
    int *pmax, *pmin;
    pmax = p;
    pmin = p;
    for (i = 0; i < 5; i++) //找最大值和最小值的地址栈幸,并賦給 pmax,pmin
        for (j = i; j < 5; j++)
        {
            if (*pmax < *(p + 5 * i + j))
                pmax = p + 5 * i + j;
            if (*pmin > *(p + 5 * i + j))
                pmin = p + 5 * i + j;
        }
    temp = *(p + 12); //將最大值換給中心元素
    *(p + 12) = *pmax;
    *pmax = temp;
    temp = *p; //將最小值換給左上角元素
    *p = *pmin;
    *pmin = temp;
    pmin = p + 1;
    for (i = 0; i < 5; i++) //找第二最小值的地址并賦給 pmin
        for (j = 0; j < 5; j++)
            if (((p + 5 * i + j) != p) && (*pmin > *(p + 5 * i + j)))
                pmin = p + 5 * i + j;
    temp = *pmin; //將第二最小值換給右上角元素
    *pmin = *(p + 4);
    *(p + 4) = temp;
    pmin = p + 1;
    for (i = 0; i < 5; i++) //找第三最小值的地址并賦給 pmin
        for (j = 0; j < 5; j++)
            if (((p + 5 * i + j) != (p + 4)) && ((p + 5 * i + j) != p) && (*pmin > *(p + 5 * i + j)))
                pmin = p + 5 * i + j;
    temp = *pmin; //將第三最小值換給左下角元素
    *pmin = *(p + 20);
    *(p + 20) = temp;
    pmin = p + 1; //找第四最小值的地址并賦給 pmin
    for (i = 0; i < 5; i++)
        for (j = 0; j < 5; j++)
            if (((p + 5 * i + j) != p) && ((p + 5 * i + j) != (p + 4)) && ((p + 5 * i + j) != (p + 20)) && (*pmin > *(p + 5 * i + j)))
                pmin = p + 5 * i + j;
    temp = *pmin; //將第四最小值換給右下角元素
    *pmin = *(p + 24);
    *(p + 24) = temp;
}

運(yùn)行結(jié)果:

WX20220328-175034@2x.png

說(shuō)明:程序中用 change 函數(shù)來(lái)實(shí)現(xiàn)題目所要求的元素值的交換帮辟,分為以下幾個(gè)步驟:

①找出全部元素中的最大值和最小值,將最大值與中心元素互換玩焰,將最小值與左上角元素互換由驹。中心元素的地址為p+12(該元素是數(shù)組中的第 12 個(gè)元素——序號(hào)從 0 算起)。

②找出全部元素中的次小值昔园。由于最小值已找到并放在 a[0][0]中蔓榄,因此,在這一輪的比較中應(yīng)不包括a[0][0]默刚,在其余 24 個(gè)元素中值最小的就是全部元素中的次小值甥郑。在雙重 for 循環(huán)中應(yīng)排除 a[0][0]參加比較。在 if 語(yǔ)句中荤西,只有滿(mǎn)足條件 ((p+5*i+j)!=p) 才進(jìn)行比較澜搅。不難理解伍俘, (p+5*i+j) 就是 &a[i][j] ,p 的值是 &a[0][0] 勉躺。((p+5*i+j)!=p) 意味著在 i 和 j 的當(dāng)前值條件下 &a[i][j] 不等于 &a[0][0] 才滿(mǎn)足條件癌瘾,這樣就排除了 a[0][0] 。因此執(zhí)行雙重 for 循環(huán)后得到次小值饵溅,并將它與右上角元素互換妨退,右上角元素的地址為 p+4。

③找出全部元素中第 3 個(gè)最小值蜕企。此時(shí) a[0][0]a[0][4](即左上角和右上角元素)不應(yīng)參加比較咬荷。可以看到∶在 if 語(yǔ)句中規(guī)定轻掩,只有滿(mǎn)足條件 ((p+5*i+j)!=p)&&((p+5*i+j)!=(p+4)) 才進(jìn)行比較幸乒。((p+5*i+j)!=p) 的作用是排除 a[0][0]((p+5*i+j)!=(p+4)) 的作用是排除 a[0][4] 放典。(p+5*i+j)&a[i][j] 逝变,(p+4) 是 &a[0][4] ,即右上角元素的地址奋构。滿(mǎn)足 ((p+5*i+j)!=(p+4)) 條件意味著排除了 a[0][4] 壳影。執(zhí)行雙重 for 循環(huán)后得到除了 a[0][0]a[0][4] 外的最小值,也就是全部元素中第 3 個(gè)最小值弥臼,將它與左下角元素互換宴咧,左下角元素的地址為 p+20。

④找出全部元素中第 4 個(gè)最小值径缅。此時(shí) a[0][0] 掺栅,a[0][4]a[4][0](即左上角、右上角和左下角元素)不應(yīng)參加比較纳猪,在 if 語(yǔ)句中規(guī)定氧卧,只有滿(mǎn)足條件 ((p+5*i+j)!=p)&&((p+5*i+j)!=(p+4))&&((p+5*i+j)!=(p+20)) 才進(jìn)行比較。((p+5*i+j)!=p)((p+5*i+j)!=(p+4)) 的作用前已說(shuō)明氏堤,((p+5*i+j)!=(p+20)) 的作用是排除 a[4][0] 沙绝,理由與前面介紹的類(lèi)似。執(zhí)行雙重 for 循環(huán)后得到除了 a[0][0] 鼠锈,a[0][4]a[4][0] 以外的最小值闪檬,也就是全部元素中第 4 個(gè)最小值,將它與右下角元素互換购笆,左下角元素的地址為 p+24粗悯。

上面所說(shuō)的元素地址是指以元素為單位的地址,p+24 表示從指針 p 當(dāng)前位置向前移動(dòng) 24 個(gè)元素的位置同欠。如果用字節(jié)地址表示样傍,上面右下角元素的字節(jié)地址應(yīng)為 p+4*24横缔,其中4 是整型數(shù)據(jù)所占的字節(jié)數(shù)。

(2)可以改寫(xiě)上面的 if 語(yǔ)句铭乾,change 函數(shù)可以改寫(xiě)如下∶


//交換函數(shù)
void change(int *p)
{
    int i, j, temp;
    int *pmax, *pmin;
    pmax = p;
    pmin = p;
    for (i = 0; i < 5; i++) //找最大值和最小值的地址剪廉,并賦給 pmax,pmin
        for (j = i; j < 5; j++)
        {
            if (*pmax < *(p + 5 * i + j))
                pmax = p + 5 * i + j;
            if (*pmin > *(p + 5 * i + j))
                pmin = p + 5 * i + j;
        }
    temp = *(p + 12); //將最大值與中心元素互換
    *(p + 12) = *pmax;
    *pmax = temp;

    temp = *p; //將最小值與左上角元素互換
    *p = *pmin;
    *pmin = temp;

    pmin = p + 1;
    //將 a[0][1]的地址賦給 pmin炕檩,從該位置開(kāi)始找最小的元素
    for (i = 0; i < 5; i++) //找第二最小值的地址并賦給 pmin
        for (j = 0; j < 5; j++)
        {
            if (i == 0 && j == 0)
                continue;
            if (*pmin > *(p + 5 * i + j))
                pmin = p + 5 * i + j;
        }
    temp = *pmin; //將第二最小值與右上角元素互換
    *pmin = *(p + 4);
    *(p + 4) = temp;

    pmin = p + 1;
    for (i = 0; i < 5; i++) //找第三最小值的地址并賦給 pmin
        for (j = 0; j < 5; j++)
        {
            if ((i == 0 && j == 0) || (i == 0 && j == 4))
                continue;
            if (*pmin > *(p + 5 * i + j))
                pmin = p + 5 * i + j;
        }
    temp = *pmin; //將第三最小值與左下角元素互換
    *pmin = *(p + 20);
    *(p + 20) = temp;

    pmin = p + 1; //找第四最小值的地址并賦給 pmin
    for (i = 0; i < 5; i++)
        for (j = 0; j < 5; j++)
        {
            if ((i == 0 && j == 0) || (i == 0 && j == 4) || (i == 4 && j == 0))
                continue;
            if (*pmin > *(p + 5 * i + j))
                pmin = p + 5 * i + j;
        }
    temp = *pmin; //將第四最小值與右下角元素互換
    *pmin = *(p + 24);
    *(p + 24) = temp;
}

這種寫(xiě)法可能更容易為一般讀者所理解斗蒋。

題目11:在主函數(shù)中輸入 10 個(gè)等長(zhǎng)的字符串。用另一函數(shù)對(duì)它們排序笛质。然后在主函數(shù)輸出這 10 個(gè)已排好序的字符串泉沾。

解∶

(1)用字符型二維數(shù)組

答案代碼:

#include <stdio.h>
#include <string.h>
int main()
{
    void sort(char s[][6]);
    int i;
    char str[10][6]; // p 是指向由 6個(gè)元素組成的一維數(shù)組的指針
    printf("input 10 strings:\n");
    for (i = 0; i < 10; i++)
        scanf("%s", str[i]);
    sort(str);
    printf("Now,the sequence is:\n");
    for (i = 0; i < 10; i++)
        printf("%s\n", str[i]);
    return 0;
}

void sort(char s[10][6]) //形參s是指向由6個(gè)元素組成的一維數(shù)組的指針
{
    int i, j;
    char *p, temp[10];
    p = temp;
    for (i = 0; i < 9; i++)
        for (j = 0; j < 9 - i; j++)
            if (strcmp(s[j], s[j + 1]) > 0)
            {
                //以下3行是將s[i]指向的一維數(shù)組的內(nèi)容與s[j+1]指向的一維數(shù)組的內(nèi)容互換
                strcpy(p, s[j]);
                strcpy(s[j], s[+j + 1]);
                strcpy(s[j + 1], p);
            }
}

運(yùn)行結(jié)果:

WX20220329-093652@2x.png

(2) 用指向一維數(shù)組的指針作函數(shù)參數(shù)

#include <stdio.h>
#include <string.h>
int main()
{
    void
    sort(char(*p)[6]);
    int i;
    char str[10][6];
    char(*p)[6];
    printf("input 10 strings:\n");
    for (i = 0; i < 10; i++)
        scanf("%s", str[i]);
    p = str;
    sort(p);
    printf("Now, the sequence is:\n");
    for (i = 0; i < 10; i++)
        printf("%s\n", str[i]);
    return 0;
}

void sort(char (*s)[6])
{
    int i, j;
    char temp[6], *t = temp;
    for (i = 0; i < 9; i++)
        for (j = 0; j < 9 - i; j++)
            if (strcmp(s[j], s[j + 1]) > 0)
            {
                strcpy(t, s[j]);
                strcpy(s[j], s[+j + 1]);
                strcpy(s[j + 1], t);
            }
}

運(yùn)行結(jié)果同(1)。

題目12:用指針數(shù)組處理上一題目妇押,字符串不等長(zhǎng)跷究。

解:

答案代碼:

#include <stdio.h>
#include <string.h>
int main()
{
    void sort(char *[]);
    int i;
    char *p[10], str[10][20];
    for (i = 0; i < 10; i++)
        p[i] = str[i]; //將第i個(gè)字符串的首地址賦予指針數(shù)組 p的第i個(gè)元素
    printf("input 10 strings:\n");
    for (i = 0; i < 10; i++)
        scanf("%s", p[i]);
    sort(p);
    printf("Now,the sequence is:\n");
    for (i = 0; i < 10; i++)
        printf("%s\n", p[i]);
    return 0;
}
void sort(char *s[])
{
    int i, j;
    char *temp;
    for (i = 0; i < 9; i++)
        for (j = 0; j < 9 - i; j++)
            if (strcmp(*(s + j), *(s + j + 1)) > 0)
            {
                temp = *(s + j);
                *(s + j) = *(s + j + 1);
                *(s + j + 1) = temp;
            }
}

運(yùn)行結(jié)果:

WX20220329-094830@2x.png

題目13:寫(xiě)一個(gè)用矩形法求定積分的通用函數(shù),分別求

\int _0^1 sinxdx, \int _0^1 cosxdx,\int_0^1e^xdx

說(shuō)明:sin敲霍,cos俊马,exp 函數(shù)已在系 統(tǒng)的數(shù)學(xué)函數(shù)庫(kù)中,程序 開(kāi)頭要用 # include <math.h>肩杈。

解:

可以看出柴我,每次需要求定積分的函數(shù)是不一樣的±┤唬可以編寫(xiě)一個(gè)求定積分的通用函數(shù) integral艘儒,它有3個(gè)形參,即下限 a夫偶、上限 b及指向函數(shù)的指針變量 fun界睁。函數(shù)原型可寫(xiě)為

float integral(float a, float b,float(* fun)());

先后調(diào)用integral函數(shù)3次,每次調(diào)用時(shí)把 a兵拢,b翻斟,sin,cos说铃,exp 之一作為實(shí)參杨赤,把上限、下限及有關(guān)函數(shù)的入口地址傳送給形參 fun截汪。在執(zhí)行 integral 函數(shù)過(guò)程中求出定積分的值。根據(jù)以上思路編寫(xiě)出程序:

#include <stdio.h>
#include <math.h>
int main()
{
    float integral(float (*)(float), float, float, int); //對(duì) integarl函數(shù)的聲明
    float fsin(float);                                   //對(duì) fsin 函數(shù)的聲明
    float fcos(float);                                   //對(duì) fcos 函數(shù)的聲明
    float fexp(float);                                   //對(duì)fexp 函數(shù)的聲明
    float a1, b1, a2, b2, a3, b3, c, (*p)(float);
    int n = 20;
    printf("input a1,b1:");
    scanf("%f,%f", &a1, &b1); //輸入求 sin(x)定積分的下限和上限
    printf("input a2,b2:");
    scanf("%f,%f", &a2, &b2); //輸入求 cos(x)定積分的下限和上限
    printf("input a3,b3:");
    scanf("%f,%f", &a3, &b3);   //輸入求e的x次方的定積分的下限和上限
    p = fsin;                   //使p指向 fsin 函數(shù)
    c = integral(p, a1, b1, n); //求出 sin(x)的定積分
    printf("The integral of sin(x)is:%f\n", c);
    p = fcos;                   //使 p指向fcos 函數(shù)
    c = integral(p, a2, b2, n); //求出 cos(x)的定積分
    printf("The integral of cos(x)is:%f\n", c);
    p = fexp;                   //使p指向 fexp 函數(shù)
    c = integral(p, a3, b3, n); //求出e的x次方的定積分
    printf("The integral of exp(x)is:%f\n", c);
    return 0;
}

//下面是用矩形法求定積分的通用函數(shù)
float integral(float (*p)(float), float a, float b, int n)
{
    int i;
    float x, h, s;
    h = (b - a) / n;
    x = a;
    s = 0;
    for (i = 1; i <= n; i++)
    {
        x = x + h;
        s = s + (*p)(x)*h;
    }
    return (s);
}

float fsin(float x) //計(jì)算 sin(x)的函數(shù)
{
    return sin(x);
}

float fcos(float x) //計(jì)算 cos(x)的函數(shù)
{
    return cos(x);
}
float fexp(float x) //計(jì)算e的 x次方的函數(shù)
{
    return exp(x);
}

運(yùn)行結(jié)果:

WX20220329-100130@2x.png

說(shuō)明:sin植捎,cos 和 exp 是系統(tǒng)提供的數(shù)學(xué)函數(shù)衙解,在程序中定義3 個(gè)函數(shù),即 fsin焰枢,fcos 和 fexp蚓峦。分別用來(lái)計(jì)算 sin(x) 舌剂,cos(x) 和exp(x) 的值。在 main 函數(shù)中要對(duì)這 3 個(gè)函數(shù)作聲明暑椰。在 main 函數(shù)定義中 p為指向函數(shù)的指針變量霍转,定義形式是"float(*p)(float)",表示 p 指向的函數(shù)有一個(gè)實(shí)型形參一汽,p 指向返回值為實(shí)型的函數(shù)避消。在 main 函數(shù)中有"p=fsin;",表示將 fsin 函數(shù)的入口地址傳賦給 p召夹,在調(diào)用 integral 函數(shù)時(shí)岩喷,用 p 作為實(shí)參,把 fsin 函數(shù)的入口地址傳遞給形參 p(相當(dāng)于 fsin(x) 监憎。fsin(x) 的值就是 sin(x)的值纱意。因此通過(guò)調(diào)用 integral 函數(shù)求出 sin(x) 的定積分。求其余兩個(gè)函數(shù)的定積分的情況與此類(lèi)似鲸阔。

題目14:將 n 個(gè)數(shù)按輸入時(shí)順序的逆序排列偷霉,用函數(shù)實(shí)現(xiàn)。

解:

答案代碼:

#include <stdio.h>
int main()
{
    void sort(char *p, int m);
    int i, n;
    char *p, num[20];
    printf("input n:");
    scanf("%d", &n);
    printf("please input these numbers: \n");
    for (i = 0; i < n; i++)
        scanf("%d", &num[i]);
    p = &num[0];
    sort(p, n);
    printf("Now,the sequence is:\n");
    for (i = 0; i < n; i++)
        printf("%d ", num[i]);
    printf("\n");
    return 0;
}

//將n 個(gè)數(shù)逆序排列函數(shù)
void sort(char *p, int m)
{
    int i;
    char temp, *p1, *p2;
    for (i = 0; i < m / 2; i++)
    {
        p1 = p + i;
        p2 = p + (m - 1 - i);
        temp = *p1;
        *p1 = *p2;
        *p2 = temp;
    }
}

運(yùn)行結(jié)果:

WX20220329-101653@2x.png

題目15:有一個(gè)班 4 個(gè)學(xué)生褐筛,5 門(mén)課程类少。

①求第 1 門(mén)課程的平均分;

②找出有兩門(mén)以上課程不及格的學(xué)生,輸出他們的學(xué)號(hào)和全部課程成績(jī)及平均成績(jī);

③找出平均成績(jī)?cè)?90 分以上或全部課程成績(jī)?cè)?85分以上的學(xué)生死讹。

分別編3個(gè)函數(shù)實(shí)現(xiàn)以上 3個(gè)要求专缠。

解:

答案代碼:

#include <stdio.h>
int main()

{
    void avsco(float *, float *);                                            //函數(shù)聲明
    void avcour1(char(*)[10], float *);                                      //函數(shù)聲明
    void fali2(char course[5][10], int num[], float *pscore, float aver[4]); //函數(shù)聲明
    void good(char course[5][10], int num[4], float *pscore, float aver[4]); //函數(shù)聲明
    int i, j, *pnum, num[4];
    float score[4][5], aver[4], *pscore, *paver;
    char course[5][10], (*pcourse)[10];
    printf("input course:\n");
    pcourse = course;
    for (i = 0; i < 5; i++)
        scanf("%s", course[i]);
    printf("input NO. and scores:\n");
    printf("NO.");
    for (i = 0; i < 5; i++)
        printf(",%s", course[i]);
    printf("\n");
    pscore = &score[0][0];
    pnum = &num[0];
    for (i = 0; i < 4; i++)
    {
        scanf("%d", pnum + i);
        for (j = 0; j < 5; j++)
            scanf("%f", pscore + 5 * i + j);
    }
    paver = &aver[0];
    printf("\n\n");
    avsco(pscore, paver);     //求出每個(gè)學(xué)生的平均成績(jī)
    avcour1(pcourse, pscore); //求出第 1 門(mén)課的平均成績(jī)
    printf("\n\n");
    fali2(pcourse, pnum, pscore, paver); //找出兩門(mén)課不及格的學(xué)生
    printf("\n\n");
    good(pcourse, pnum, pscore, paver); //找出成績(jī)好的學(xué)生
    return 0;
}

//求每個(gè)學(xué)生的平均成績(jī)的函數(shù)
void avsco(float *pscore, float *paver)
{
    int i, j;
    float sum, average;
    for (i = 0; i < 4; i++)
    {
        sum = 0.0;
        for (j = 0; j < 5; j++)
            sum = sum + (*(pscore + 5 * i + j)); //累計(jì)每個(gè)學(xué)生的各科成績(jī)
        average = sum / 5;                       //計(jì)算平均成績(jī)
        *(paver + i) = average;
    }
}

//求第1課程的平均成績(jī)的函數(shù)
void avcour1(char (*pcourse)[10], float *pscore)
{
    int i;
    float sum, average1;
    sum = 0.0;
    for (i = 0; i < 4; i++)
        sum = sum + (*(pscore + 5 * i)); //累計(jì)每個(gè)學(xué)生的得分
    average1 = sum / 4;                  //計(jì)算平均成績(jī)
    printf("course 1:%s average score:%7.2f\n", *pcourse, average1);
}

//找兩門(mén)以上課程不及格的學(xué)生的函數(shù)
void fali2(char course[5][10], int num[], float *pscore, float aver[4])
{
    int i, j, k, label;
    printf("    ======Student who is fail in two courses ======\n");
    printf("NO. ");
    for (i = 0; i < 5; i++)
        printf("%11s", course[i]);
    printf("    average\n");
    for (i = 0; i < 4; i++)
    {
        label = 0;
        for (j = 0; j < 5; j++)
            if (*(pscore + 5 * i + j) < 60.0)
                label++;
        if (label >= 2)
        {
            printf("%d", num[i]);
            for (k = 0; k < 5; k++)
                printf("%11.2f", *(pscore + 5 * i + k));
            printf("%11.2f\n ", aver[i]);
        }
    }
}

//找成績(jī)優(yōu)秀學(xué)生(各門(mén)85分以上或平均 90分以上)的函數(shù)
void good(char course[5][10], int num[4], float *pscore, float aver[4])
{
    int i, j, k, n;
    printf("    ======Students whose score is good ======\n");
    printf("NO. ");
    for (i = 0; i < 5; i++)
        printf("%11s", course[i]);
    printf("    average\n");
    for (i = 0; i < 4; i++)
    {
        n = 0;
        for (j = 0; j < 5; j++)
            if (*(pscore + 5 * i + j) > 85.0)
                n++;
        if ((n == 5) || (aver[i] >= 90))
        {
            printf("%d", num[i]);
            for (k = 0; k < 5; k++)
                printf("%11.2f", *(pscore + 5 * i + k));
            printf("%11.2f\n", aver[i]);
        }
    }
}

運(yùn)行結(jié)果:

WX20220329-104624@2x.png

程序中 num 是存放 4 個(gè)學(xué)生學(xué)號(hào)的一維數(shù)組,course 是存放 5 門(mén)課名稱(chēng)的二維字符數(shù)組苟穆,score 是存放 4 個(gè)學(xué)生 5 門(mén)課成績(jī)的二維數(shù)組甲喝,aver 是存放每個(gè)學(xué)生平均成績(jī)的數(shù)組。pnum 是指向 num數(shù)組的指針變量愧旦,pcou 是指向 course 數(shù)組的指針變量世剖,psco 是指向 score 數(shù)組的指針變量,pave是指向 aver 數(shù)組的指針變量笤虫,見(jiàn)圖8.3旁瘫。

WX20220329-104707@2x.png

函數(shù)的形參用數(shù)組,調(diào)用函數(shù)時(shí)的實(shí)參用指針變量琼蚯。形參也可以不用數(shù)組而用指針變量酬凳,請(qǐng)讀者自己分析。

題目16:輸入一個(gè)字符串遭庶,內(nèi)有數(shù)字和非數(shù)字字符宁仔,例如∶

A123x456 17960?302tab5876

將其中連續(xù)的數(shù)字作為一個(gè)整數(shù),依次存放到一數(shù)組 a 中峦睡。例如翎苫,123放在 a[0]权埠,456放在a[1]……統(tǒng)計(jì)共有多少個(gè)整數(shù),并輸出這些數(shù)煎谍。

解∶

答案代碼:

#include <stdio.h>
int main()
{
    char str[50], *pstr;
    int i, j, k, m, e10, digit, ndigit, a[10], *pa;
    printf("input a string:\n");
    gets(str);
    pstr = &str[0]; //字符指針 pstr置于數(shù)組 str 首地址
    pa = &a[0];     //指針 pa 置于a數(shù)組首地址
    ndigit = 0;     // ndigit 代表有多少個(gè)整數(shù)
    i = 0;          //代表字符串中的第幾個(gè)字符
    j = 0;
    while (*(pstr + i) != '\0')
    {
        if ((*(pstr + i) >= '0') && (*(pstr + i) <= '9'))
            j++;
        else
        {
            if (j > 0)
            {
                digit = *(pstr + i - 1) - 48; //將個(gè)數(shù)位賦予digit
                k = 1;
                while (k < j) //將含有兩位以上數(shù)的其他位的數(shù)值累加于digit
                {
                    e10 = 1;
                    for (m = 1; m <= k; m++)
                        e10 = e10 * 10;                               // e10 代表該位數(shù)所應(yīng)乘的因子
                    digit = digit + (*(pstr + i - 1 - k) - 48) * e10; //將該位數(shù)的數(shù)值\累加于 digit
                    k++;                                              //位數(shù)k自增
                }
                *pa = digit; //將數(shù)值賦予數(shù)組 a
                ndigit++;
                pa++; //指針 pa 指向 a數(shù)組下一元素
                j = 0;
            }
        }
        i++;
    }
    if (j > 0) //以數(shù)字結(jié)尾字符串的最后一個(gè)數(shù)據(jù)
    {
        digit = *(pstr + i - 1) - 48; //將個(gè)數(shù)位賦予 digit
        k = 1;
        while (k < j)
        {
            e10 = 1; //將含有兩位以上數(shù)的其他位的數(shù)值累加于 digit
            for (m = 1; m <= k; m++)
                e10 = e10 * 10;                               // e10代表位數(shù)所應(yīng)乘的因子
            digit = digit + (*(pstr + i - 1 - k) - 48) * e10; //將該位數(shù)的數(shù)值累加于 digit
            k++;                                              //位數(shù)k自增
        }
        *pa = digit; //將數(shù)值賦予數(shù)組 a
        ndigit++;
        j = 0;
    }
    printf("There are %d numbers in this line, they are:\n", ndigit);
    j = 0;
    pa = &a[0];
    for (j = 0; j < ndigit; j++) //輸出打印數(shù)據(jù)
        printf("%d ", *(pa + j));
    printf("\n");
    return 0;
}

運(yùn)行結(jié)果:

WX20220329-135612@2x.png

題目17:寫(xiě)一函數(shù)攘蔽,實(shí)現(xiàn)兩個(gè)字符串的比較。即自己寫(xiě)一個(gè) strcmp 函數(shù)呐粘,函數(shù)原型為

int strcmp(char * p1,char * p2);

設(shè) p1指向字符串sl满俗,p2指向字符串s2。要求當(dāng)s1=s2時(shí)事哭,返回值為0;若 s1≠s2漫雷,返回它們二者第 1 個(gè)不同字符的 ASCII 碼差值(如"BOY"與"BAD",第 2個(gè)字母不同鳍咱,O與 A 之差為79-65=14)降盹。如果 s1>s2,則輸出正值;如果 s1<s2谤辜,則輸出負(fù)值蓄坏。

解:

答案代碼:

#include <stdio.h>
int main()
{
    int m;
    char str1[20], str2[20], *p1, *p2;
    printf("input two strings:\n");
    scanf("%s", str1);
    scanf("%s", str2);
    p1 = &str1[0];
    p2 = &str2[0];
    m = strcmp(p1, p2);
    printf("result:%d,\n", m);
    return 0;
} //兩個(gè)字符串比較函數(shù)
strcmp(char *p1, char *p2)
{
    int i;
    i = 0;
    while (*(p1 + i) == *(p2 + i))
        if (*(p1 + i++) == '\0') //相等時(shí)返回結(jié)果0
            return (0);
    return (*(p1 + i) - *(p2 + i)); /*不等時(shí)返回結(jié)果為第一個(gè)不等字符ASCII碼的差值 */
}

運(yùn)行結(jié)果∶

①:

WX20220329-141210@2x.png

②:

WX20220329-141428@2x.png

題目18:編一程序,輸入月份號(hào)丑念,輸出該月的英文月名涡戳。例如,輸入 3脯倚,則輸出"March"渔彰,要求用指針數(shù)組處理。

解:

答案代碼:

#include <stdio.h>
int main()
{
    char *month_name[13] = {"illegal month ", " January", " February", " March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
    int n;
    printf("input month:\n");
    scanf("%d", &n);
    if ((n <= 12) && (n >= 1))
        printf("It is %s.\n", *(month_name + n));
    else
        printf("It is wrong.\n");
    return 0;
}

運(yùn)行結(jié)果∶

①:

WX20220329-142351@2x.png

②:

WX20220329-142405@2x.png

③:

WX20220329-142419@2x.png

題目19:(1)編寫(xiě)一個(gè)函數(shù) new推正,對(duì) n 個(gè)字符開(kāi)辟連續(xù)的存儲(chǔ)空間恍涂,此函數(shù)應(yīng)返回一個(gè)指針(地址),指向字符串開(kāi)始的空間植榕。new(n)表示分配 n 個(gè)字節(jié)的內(nèi)存空間再沧。(2)寫(xiě)一函數(shù) free;將 前面用 new 函數(shù)占用的空間釋放。free(p)表示將 p(地址))指向的單元以后的內(nèi)存段釋放尊残。

解∶

(1)編寫(xiě)函數(shù)new 程序如下∶

#include <stdio.h>
#define NEWSIZE 1000  //指定開(kāi)辟存儲(chǔ)區(qū)的最大容量
char newbuf[NEWSIZE]; //定義字符數(shù)組 newbuf
char *newp = newbuf;  //定義指針變量 newp炒瘸,指向可存儲(chǔ)區(qū)的始端

//定義開(kāi)辟存儲(chǔ)區(qū)的函數(shù) new,開(kāi)辟存儲(chǔ)區(qū)后返回指針
char *new (int n)
{
    if (newp + n <= newbuf + NEWSIZE) //開(kāi)辟區(qū)未超過(guò) newbuf 數(shù)組的大小
    {
        newp += n;         // newp指向存儲(chǔ)區(qū)的末尾
        return (newp - n); //返回一個(gè)指針寝衫,它指向存儲(chǔ)區(qū)的開(kāi)始位置
    }
    else
        return (NULL); //當(dāng)存儲(chǔ)區(qū)不夠分配時(shí)顷扩,返回一個(gè)空指針
}

new 函數(shù)的作用是:分配 n 個(gè)連續(xù)字符的存儲(chǔ)空間。為此慰毅,應(yīng)先開(kāi)辟一個(gè)足夠大的連續(xù)存儲(chǔ)區(qū)屎即,今設(shè)置字符數(shù)組 newbuf[1000],new 函數(shù)將在此范圍內(nèi)進(jìn)行操作。指針變量 newp 開(kāi)始指向存儲(chǔ)區(qū)首字節(jié)技俐。在每當(dāng)請(qǐng)求用 new 函數(shù)開(kāi)辟 n 個(gè)字符的存儲(chǔ)區(qū)時(shí),要先檢查一下 newbuf 數(shù)組是否還有足夠的可用空間统台。若有雕擂,則使指針變量 newp 指向開(kāi)辟區(qū)的末尾(newp=newp十n),見(jiàn)圖8.4中的 newp 贱勃。此時(shí) newp 指向下面的空白(未分配)的區(qū)域的開(kāi)頭井赌,即 newp 的值是下一次可用空間的開(kāi)始地址。如果再一次調(diào)用 new 函數(shù)贵扰,就從 newp 最后所指向的字節(jié)開(kāi)始分配下一個(gè)開(kāi)辟區(qū)仇穗。如果若存儲(chǔ)區(qū)不夠分配,則返回 NULL戚绕,表示開(kāi)辟失敗纹坐。

WX20220329-142545@2x.png

new返回一個(gè)指向字符型數(shù)據(jù)的指針,指向新開(kāi)辟的區(qū)域的首字節(jié)舞丛。

在主函數(shù)中可以用以下語(yǔ)句:

pt = new(n);

把新開(kāi)辟的區(qū)域首字節(jié)的地址賦給 pt耘子,使指針變量 pt 也指向新開(kāi)辟的區(qū)域的開(kāi)頭。

(2)編寫(xiě)函數(shù) free

free 的作用是使newp 的值恢復(fù)為p球切。

free 函數(shù)如下∶

#include <stdio.h>
#define NEWSIZE 1000
char newbuf[NEWSIZE];
char *newp = newbuf;

//釋放存區(qū)函數(shù)
void free(char *p)
{
    if (p >= newbuf && p < newbuf + NEWSIZE)
        newp = p;
}

在主函數(shù)中用以下語(yǔ)句指令釋放 pt 指向的存儲(chǔ)區(qū)谷誓。

free(pt);

調(diào)用 free時(shí),實(shí)參 pt 的值傳給形參 p吨凑,因此 p的值也是新開(kāi)辟的區(qū)域首字節(jié)的地址捍歪。用 if 語(yǔ)句檢查 p 是否在已開(kāi)辟區(qū)的范圍內(nèi)(否則不合法,不能釋放未分配的區(qū)域)鸵钝。如果確認(rèn) p 在上述范圍內(nèi)糙臼,就把 p(即 pt)的值賦給 newp,使 newp 重新指向原來(lái)開(kāi)辟區(qū)的開(kāi)頭蒋伦,這樣弓摘,下次再開(kāi)辟新區(qū)域時(shí)就又從 newp 指向的字節(jié)開(kāi)始分配,這就相當(dāng)于釋放了此段空間痕届,使這段空間可再分配作其他用途韧献。

有人可能對(duì) if語(yǔ)句所檢查的條件 "p>=newbuf && p<newbuf + NEWSIZE" 不理解,為什么不直接檢查 "p==newbuf" 呢?他們認(rèn)為 p 應(yīng)當(dāng)指向 newbuf 的開(kāi)頭研叫。這里有個(gè)細(xì)節(jié)要考慮∶當(dāng)?shù)?1 次調(diào)用 new 函數(shù)開(kāi)辟存儲(chǔ)區(qū)時(shí)锤窑,new 函數(shù)的返回值(也是 pt 的值)的確是 newbuf。但是如果接著再開(kāi)辟第 2 個(gè)存儲(chǔ)區(qū)嚷炉,new 函數(shù)的返回值(也是 pt 的值)就不是newbuf了渊啰,而是指針變量 newp的當(dāng)前值,即 newbuf+n了。因此绘证,調(diào)用free 函數(shù)時(shí)隧膏,形參p得到的值也是第 2個(gè)存儲(chǔ)區(qū)的起始地址。要釋放的是第 2個(gè)存儲(chǔ)區(qū)嚷那,而不是第1個(gè)存儲(chǔ)區(qū)胞枕。但p的值必然在"newbuf 到 newbuf+NEWSIZE"的范圍內(nèi)。

上面只是編寫(xiě)了兩個(gè)函數(shù)魏宽,并不是完整的程序腐泻,它沒(méi)有main 函數(shù)。本題是示意性的队询,可以大體了解開(kāi)辟存儲(chǔ)區(qū)的思路派桩。

題目20:用指向指針的指針的方法對(duì) 5個(gè)字符串排序并輸出。

解:

程序如下

#include <stdio.h>
#include <string.h>
#define LINEMAX 20 //定義字符串的最大長(zhǎng)度
int main()
{
    void sort(char **p);
    int i;
    char **p, *pstr[5], str[5][LINEMAX];
    for (i = 0; i < 5; i++)
        pstr[i] = str[i]; //將第i個(gè)字符串的首地址賦予指針數(shù)組 pstr 的第i個(gè)元素
    printf("input 5 strings:\n");
    for (i = 0; i < 5; i++)
        scanf("%s", pstr[i]);
    p = pstr;
    sort(p);
    printf("\nstrings sorted:\n");
    for (i = 0; i < 5; i++)
        printf("%s\n", pstr[i]);
    return 0;
}
//用冒泡法對(duì)5個(gè)字符串排序函數(shù)
void sort(char **p)
{
    int i, j;
    char *temp;
    for (i = 0; i < 5; i++)
    {
        for (j = i + 1; j < 5; j++) //比較后交換字符串地址
        {
            if (strcmp(*(p + i), *(p + j)) > 0)
            {
                temp = *(p + i);
                *(p + i) = *(p + j);
                *(p + j) = temp;
            }
        }
    }
}

運(yùn)行結(jié)果:

WX20220329-145701@2x.png

題目21:用指向指針的指針的方法對(duì) n個(gè)整數(shù)排序并輸出蚌斩。要求將排序單獨(dú)寫(xiě)成一個(gè)函數(shù)铆惑。n 個(gè)整數(shù)在主函數(shù)中輸入,最后在主函數(shù)中輸出凳寺。

解:

答案代碼:

#include <stdio.h>
int main()
{
    void sort(int **p, int n);
    int i, n, data[20], **p, *pstr[20];
    printf("input n:\n");
    scanf("%d", &n);
    for (i = 0; i < n; i++)
        pstr[i] = &data[i]; //將第i個(gè)整數(shù)的地址賦予指針數(shù)組 pstr 的第i個(gè)元素
    printf("input %d integer numbers:", n);
    for (i = 0; i < n; i++)
        scanf("%d", pstr[i]);
    p = pstr;
    sort(p, n);
    printf("Now,the sequence is:\n");
    for (i = 0; i < n; i++)
        printf("%d ", *pstr[i]);
    printf("\n");
    return 0;
}
void sort(int **p, int n)
{
    int i, j, *temp;
    for (i = 0; i < n - 1; i++)
    {
        for (j = i + 1; j < n; j++)
        {
            if (**(p + i) > **(p + j)) //比較后交換整數(shù)地址
            {
                temp = *(p + i);
                *(p + i) = *(p + j);
                *(p + j) = temp;
            }
        }
    }
}

運(yùn)行結(jié)果:

WX20220329-151244@2x.png

data數(shù)組用來(lái)存放n個(gè)整數(shù)鸭津,pstr 是指針數(shù)組,每一個(gè)元素指向 data 數(shù)組中的一個(gè)元素肠缨,p 是指向指針的指針逆趋,請(qǐng)參考圖8.5。圖8.5(a)表示的是排序前的情況晒奕,圖8.5(b)表示的是排序后的情況闻书。可以看到脑慧,data 數(shù)組中的數(shù)的順序沒(méi)有變化魄眉,而 pstr 指針數(shù)組中的各元素的值(也就是它們的指向)改變了。

WX20220329-145842@2x.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末闷袒,一起剝皮案震驚了整個(gè)濱河市坑律,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌囊骤,老刑警劉巖晃择,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異也物,居然都是意外死亡宫屠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)滑蚯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)浪蹂,“玉大人抵栈,你說(shuō)我怎么就攤上這事±ご危” “怎么了古劲?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)缰猴。 經(jīng)常有香客問(wèn)我绢慢,道長(zhǎng),這世上最難降的妖魔是什么洛波? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮骚露,結(jié)果婚禮上蹬挤,老公的妹妹穿的比我還像新娘。我一直安慰自己棘幸,他們只是感情好焰扳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著误续,像睡著了一般吨悍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹋嵌,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天育瓜,我揣著相機(jī)與錄音,去河邊找鬼栽烂。 笑死躏仇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腺办。 我是一名探鬼主播焰手,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怀喉!你這毒婦竟也來(lái)了书妻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤躬拢,失蹤者是張志新(化名)和其女友劉穎躲履,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體估灿,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡崇呵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了馅袁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片域慷。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出犹褒,到底是詐尸還是另有隱情抵窒,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布叠骑,位于F島的核電站李皇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宙枷。R本人自食惡果不足惜掉房,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望慰丛。 院中可真熱鬧卓囚,春花似錦、人聲如沸诅病。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贤笆。三九已至蝇棉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芥永,已是汗流浹背篡殷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恤左,地道東北人贴唇。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像飞袋,于是被迫代替她去往敵國(guó)和親戳气。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容