通过参数传递功能和铸造

时间:2018-05-15 06:32:10

标签: c

我是C语言的新手,在下面的练习中我有一些误解:

void printAllStrings(const char** arr[])
{
    while(*arr!=NULL)
    {
        char** ptr=(char**)*arr;
        while(*ptr!=NULL)
        {
            printf("%s\n",*ptr);
            ptr++;
        }
        arr++;
    }
}

int main()
{
    char* arrP1[]={"father","mother",NULL};
    char* arrP2[]={"sister","brother","grandfather",NULL};
    char* arrP3[]={"grandmother",NULL};
    char* arrP4[]={"uncle","aunt",NULL};
    char** arrPP[]={arrP1,arrP2,arrP3,arrP4,NULL};

    printf("Before sort :\n");
    printAllStrings(arrPP);
    sort(arrPP);

    printf("\nAfter sort :\n");
    printAllStrings(arrPP);
    printf("\nMaximum length string : %s \n",maxLengthString(arrPP));

    return 0;
}    

上面的代码打印所有字符串。

我的问题是:

  1. printAllStrings函数中传递的参数(char** arr[])字符串数组,我们可以将指针传递给指针 - char** arr

  2. 这一行char** ptr=(char**)*arr的含义是什么;我强调指出这种指向char类型的指针。 但是为什么指针必须被转换为已经指向char类型?

2 个答案:

答案 0 :(得分:2)

  
      
  1. 在printAllStrings函数中传递参数(char** arr[])字符串数组,我们可以将指针传递给指针 - char** arr[]
  2.   

在上面的示例中,您有char** arr[]char** arr[](两者是相同的),因此您的“我们可以通过吗?”问题不明确。如果您询问是否可以将参数更改为(char ***arr),那么可以,因为第一级间接(例如[ ])将转换为指针。

  
      
  1. 这一行char** ptr=(char**)*arr的含义是什么;我强调指出这种指向char类型的指针。但为什么指针有   要被铸造已经指向了char类型?
  2.   

原因是您的参数为const char** arr[],然后您声明char** ptr哪个会丢弃const上的arr限定符const char **char **不一样。因此,当您尝试使用已取消引用的ptr初始化arr时,例如(char** ptr=arr;)编译器抱怨放弃const限定符。

而不是正确解决问题,例如

const char **ptr = *arr;

你“捏造”初始化以强制丢弃const限定符 - 导致ptr不保留const类型,这可能会阻止编译器在您尝试时发出警告以非常规的方式使用ptr(当你抛弃const个限定符时会发生非常糟糕的事情)

我可能错了 - 但看起来分配的重点是保留用于初始化指针数组的字符串文字const性质。因此,而不是将数组声明为:

char* arrP1[]={"father","mother",NULL};

您应该将它们声明为char的const指针数组,例如

const char *arrP1[]={"father","mother",NULL};

printAllStrings的参数然后是有意义的,如果你尝试做一些你不允许做的事情,编辑器会发出警告,例如更改字符串文字,例如如果你尝试:

arrP1[0][0] = 'l';

(编译器将抛出error: assignment of read-only location ‘*arrP1[0]

如果你通过代码一致地携带类型,你就不必在任何地方“捏造”任何演员阵容,编译器可以帮助保护你自己。例如,对类型进行简单的返工以确保您的字符串文字是const限定的(同时仍允许您对数组进行排序)可以通过以下方式完成:

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

void printAllStrings (const char **arr[])
{
    while (*arr != NULL) {
        const char **ptr = *arr;
        while (*ptr != NULL) {
            printf ("%s\n", *ptr);
            ptr++;
        }
        arr++;
    }
}

const char *maxLengthString (const char **arr[])
{
    size_t max = 0;
    const char *longest = NULL;

    while (*arr != NULL) {
        const char **ptr = *arr;
        while (*ptr != NULL) {
            size_t len = strlen (*ptr);
            if (len > max) {
                max = len;
                longest = *ptr;
            }
            ptr++;
        }
        arr++;
    }
    return longest;
}

int main (void) {

    const char *arrP1[] = {"father", "mother", NULL};
    const char *arrP2[] = {"sister", "brother", "grandfather", NULL};
    const char *arrP3[] = {"grandmother", NULL};
    const char *arrP4[] = {"uncle", "aunt", NULL};
    const char **arrPP[] = {arrP1, arrP2, arrP3, arrP4, NULL};

    printf ("Before sort :\n");
    printAllStrings (arrPP);

    // sort (arrPP);  /* you didn't post sort, so the following swaps */
    const char **tmp = arrPP[0];    /* simple swap example */
    arrPP[0] = arrPP[1];
    arrPP[1] = tmp;

    printf ("\nAfter sort :\n");
    printAllStrings (arrPP);

    printf ("\nMaximum length string : %s \n", maxLengthString (arrPP));

    return 0;
}

(您没有发布sort(),因此在元素上方只需交换显示您的arrPP保留了排序功能,并添加了maxLengthString ()的快速实施使你的最后一个声明工作 - 但请注意,它只是找到任何最长的字符串中的第一个,如果多个字符串长度相同的话)

示例使用/输出

$ ./bin/array_ptp_const_char
Before sort :
father
mother
sister
brother
grandfather
grandmother
uncle
aunt

After sort :
sister
brother
grandfather
father
mother
grandmother
uncle
aunt

Maximum length string : grandfather

仔细看看,如果您有其他问题,请告诉我。我不确定这是不是你想要的,但根据你的代码和问题,它似乎是最合乎逻辑的选择。

答案 1 :(得分:1)

我只能回答第二个问题,因为我现在无法理解第一个问题。

char** ptr=(char**)*arr;
// this is the same but maybe confusing because arr is a pointer now and it gets iterated in the loop.
char** ptr=(char**)arr[0];

arr具有类型指针(从数组中衰减)到指向char的指针。 ptr具有指向char的指针的类型指针。

正如您所看到的,ptr的参考级别低于arrarr包含指向char的类型指针的声明数组的所有指针。 (arrP1,arrP2,arrP3,arrP4)。 通过解除引用arr,您将获得指向其中一个数组的指针。(第一次迭代中的arrP1)

然后打印存储在ptr [0]中的指针指向并迭代到ptr [1]的位置,打印出来。循环arr迭代后产生指向arrP2的指针,然后再次使用ptr - 循环。

你必须记住,数组和指针在它们的用法中非常相似(但不完全相同),并且将数组传递给函数会使它衰减为指针。

编辑:大卫的答案很棒,我误解了第二个问题的重点,所以这个答案有点偏离。我会把它留在这里,因为我认为它仍然有助于理解所有指针魔法会发生什么。对于一个相关的答案,特别是关于const正确性,大卫的答案是那个。