如何将 char** 传递给需要 const char 指针的 const 数组的函数

use*_*tis 5 c arrays pointers

如下所示,我想将 定义的变量以char **x只读方式传递给函数。

\n

一本参考书显示了线性搜索源代码,该代码通过将变量作为 定义的临时参数int *x传递给函数来对定义的变量执行线性搜索。searchconst int a[]

\n

所以我想到了一个想法,如果是字符串呢?然后我写了下面的代码。

\n

gcc、clang 和 MSVC 分析可以在这里找到

\n
// Linear Search\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nint scanf_s(const char *format ,...); // for gcc and clang environment\n// int search(const char **a, int n, char *key) {       //\xe2\x80\xbb[1]not allowed in c lang specification\xe2\x87\x92NG\n// int search(char * const *a, int n, char *key) {      //\xe2\x80\xbb[2]\xe2\x87\x92NG\n// int search(const char * const *a, int n, char *key) {    //\xe2\x80\xbb[3]warning occured in gcc and clang\xef\xbc\x81\xef\xbc\x81\n// int search(char const * const *a, int n, char *key) {//\xe2\x80\xbb[4]same as above\n// int search(const char * const a[], int n, char *key) {//\xe2\x80\xbb[5]same as above\n// int search(const char *a[], int n, char *key) {      //\xe2\x80\xbb[6]I thought this was ok, but warning occured in gcc and clang\xef\xbc\x81\xef\xbc\x81\nint search(char **a, int n, char *key) {            //in conclusion, gcc,clang and MSVC only allowing this!!\n    int i = 0;\n\n    for (i = 0; i < n; i++) {\n        if (strcmp(a[i], key) == 0)\n            return i;\n    }\n    return -1;\n\n    /* or while style!! the reference book shows this style!!\n    while (1) {\n        if (i == n)\n            return -1;\n        if (strcmp(a[i], key) == 0)\n            return i;\n        i++;\n    }\n    */\n}\n\nint main(void) {\n    char **x;\n    char *ky;\n    int nx;\n    int idx;\n    int i;\n\n    puts("Linear Search");\n    printf("How many Elements??\xef\xbc\x9a");\n    scanf_s("%d", &nx);\n    \n    x = malloc(sizeof(char*) * nx);\n    if (x == NULL) {\n        printf("Pointer to Pointer x malloc failed!!\\n");\n        exit(EXIT_FAILURE);\n    }\n\n    for (i = 0; i < nx; i++) {\n        printf("x[%d]\xef\xbc\x9a", i);\n        x[i] = malloc(sizeof(char) * 35);\n        if (x[i] == NULL) {\n            printf("Pointer Array x[] malloc failed!!\\n", i);\n            exit(EXIT_FAILURE);\n        }\n        scanf_s("%s", x[i], 35);\n    }\n\n    printf("Target Value\xef\xbc\x9a");\n    ky = malloc(sizeof(char) * 35);\n    if (x == NULL) {\n        printf("target value malloc failed!!\\n");\n        exit(EXIT_FAILURE);\n    }\n    // Or\n    // ky = calloc(35, sizeof(char));\n    scanf_s("%s", ky, 35);\n\n    idx = search(x, nx, ky);\n\n    if (idx == -1)\n        puts("no target value.");\n    else\n        printf("%s is in x[%d]\xef\xbc\x81\xef\xbc\x81\\n", ky, idx);\n\n    free(ky);\n    for (i = 0; i < nx; i++) {\n        free(x[i]);\n    }\n    free(x);\n    system("pause");\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

代码const使 gcc 和 clang 显示警告,尽管 MSVC 可以编译而没有任何警告,如注释(\xe2\x80\xbb[1]~[6])所示。

\n

search那么,在函数必须接受 定义的变量作为char **x只读参数的想法下,如何编写代码呢?

\n

ukl*_*kll 5

编译器希望数组中的字符串具有const char*类型。只需将您的数据投射到const char* const*只需在调用函数时

\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n\n#define STRING_LENGTH 36\n\nint scanf_s(const char *format ,...);\n\nunsigned int search(const char* const stringArray[], unsigned int stringCount, const char* stringToSearch)\n{\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], stringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nint main(void)\n{\n    printf("Enter the count of strings: ");\n\n    unsigned int strCount;\n    scanf_s("%u", &strCount);\n\n    char* *strArray = malloc(sizeof(char*) * strCount);\n    if(strArray == NULL)\n    {\n        printf("Could not get memory for the string array!\\n");\n        return EXIT_FAILURE;\n    }\n\n    for(unsigned int i = 0; i < strCount; i++)\n    {\n        strArray[i] = calloc(sizeof(char), STRING_LENGTH);\n        if(strArray[i] == NULL)\n        {\n            printf("Could not get memory for the next string!\\n");\n            return EXIT_FAILURE;\n        }\n\n        printf("Enter %uth string (%i characters at most): ", (i + 1), (STRING_LENGTH - 1));\n        scanf_s("%s", strArray[i], STRING_LENGTH);\n    }\n\n    char* strToSearch = calloc(sizeof(char), STRING_LENGTH);\n    if(strToSearch == NULL)\n    {\n        printf("Could not get memory for the string to be searched!\\n");\n        return EXIT_FAILURE;\n    }\n\n    printf("Enter string to be searched (%i characters at most) : ", (STRING_LENGTH - 1));\n    scanf_s("%s", strToSearch, STRING_LENGTH);\n\n    unsigned int result = search((const char* const*)strArray, strCount, strToSearch);\n    if(result != UINT_MAX) {\n        printf("String found at index: %u\\n", result);\n    } else {\n        printf("String was not found!\\n");\n    }\n\n    free(strToSearch);\n    for(unsigned int i = 0; i < strCount; i++)\n    {\n        free(strArray[i]);\n    }\n    free(strArray);\n\n    return EXIT_SUCCESS;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我在您提供的链接中尝试了这段代码。在这里检查一下。输出如下:

\n
Enter the count of strings: 3\nEnter 1th string (35 characters at most): Goodbye\nEnter 2th string (35 characters at most): Cruel\nEnter 3th string (35 characters at most): World\nEnter string to be searched (35 characters at most) : Cruel\nString found at index: 1\n
Run Code Online (Sandbox Code Playgroud)\n
\n

编辑:最初的问题是关于将 a 传递char**给期望的函数const char* const a[],但在答案和问题之后,它已经以某种方式演变为保护函数中数据的最终方式。因此,我决定添加一个关于character pointers.

\n

C 字符串简短教程(带指针)

\n

使用 char* 表示字符串

\n

我们都知道指针只存储内存地址而不存储数据。\n如果您声明 a char* cptr;,它还没有指向有效的内存地址。因此,*cptr = \'a\';是无效的,编译器会为此发出警告。

\n
int main(void)\n{\n    char* cptr;\n    *cptr = \'a\'; // gcc -> warning: \xe2\x80\x98cptr\xe2\x80\x99 is used uninitialized\n    printf("*cptr: %c\\n", *cptr);\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果您尝试运行上述程序,则会导致分段错误。

\n

为了能够使用字符指针,您必须首先将其指向一个有效的内存位置,如下所示:或者您可以从另一个包含字符或字符串的char* cptr = malloc(sizeof(char) * 6);内存位置分配有效内存位置的地址。char*

\n
int main(void)\n{\n    char* cptr = malloc(sizeof(char));\n    *cptr = \'a\';\n    printf("*cptr: %c\\n", *cptr);\n    free(cptr);\n\n    cptr = malloc(sizeof(char) * 6);\n    strcpy(cptr, "Hello\\0");\n    printf("*cptr: %s\\n", cptr);\n    free(cptr);\n    \n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出是:

\n
*cptr: a\n*cptr: Hello\n
Run Code Online (Sandbox Code Playgroud)\n

的长度character array并不重要,char*因为它始终只指向第一个字符的地址,并假设字符串以连续空格末尾的空字符 (\\0) 结尾。

\n

const 与 char* 的用法

\n

在解释了 的声明和用法之后char*,现在是时候解释const关键字与字符指针的用法了。

\n

回想一下,指针可以为我们提供 3 个不同的值:它们本身的地址、它们指向的地址以及它们指向的地址处的数据。

\n

我们无法更改指针的地址,但可以更改指针的其他属性。

\n

在上一个程序中,您看到*cptr第一个指向仅包含一个字符的内存位置。之后,它被设置为指向另一个最多可以存储6个字符(包括\\0字符)的位置。该用法是如何更改指针指向的地址的示例。

\n

如果您不希望指针指向另一个位置,则需要在const指针名称之前使用关键字,如下所示:char* const cptr

\n
int main(void)\n{\n    char* const cptr = malloc(sizeof(char));\n    *cptr = \'a\';\n    printf("*cptr: %c\\n", *cptr);\n    free(cptr);\n\n    cptr = malloc(sizeof(char) * 6); // gcc -> error: assignment of read-only variable \xe2\x80\x98cptr\xe2\x80\x99\n    strcpy(cptr, "Hello\\0");\n    printf("*cptr: %s\\n", cptr);\n    free(cptr);\n    \n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在上面的程序中,编译器不允许在整个程序执行过程中为指向同一位置的*cptr行分配新地址。cptr = malloc(sizeof(char) * 6); *cptr

\n

除了更改指针指向的地址之外,您还可以更改指向地址的数据。这可以通过这样的事情来完成:strcpy(cptr, "Hello\\0");

\n
int main(void)\n{\n    char* const cptr = malloc(sizeof(char));\n    *cptr = \'a\';\n    printf("*cptr: %c\\n", *cptr);\n    *cptr = \'b\';\n    printf("*cptr: %c\\n", *cptr);\n//  cptr = malloc(sizeof(char)); // gcc -> error: assignment of read-only variable \xe2\x80\x98cptr\xe2\x80\x99\n    free(cptr);\n\n\n    char* const sptr = malloc(sizeof(char) * 6);\n    strcpy(sptr, "Hello\\0");\n    printf("*sptr: %s\\n", sptr);\n    strcpy(sptr, "World\\0");\n    printf("*sptr: %s\\n", sptr);\n//  sptr = malloc(sizeof(char) * 6); // gcc -> error: assignment of read-only variable \xe2\x80\x98sptr\xe2\x80\x99\n    free(sptr);\n    \n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

您将得到的输出是:

\n
*cptr: a\n*cptr: b\n*sptr: Hello\n*sptr: World\n
Run Code Online (Sandbox Code Playgroud)\n

在上面的程序中,虽然不能改变指针*cptr和指向的地址*sptr,但是可以改变指向地址的数据。

\n

如果要保护 指向的地址*cptr而不是指向的地址处的数据怎么办?在下面的程序中,const char* cptr可以设置为指向两者*newCharPtr1,并且*newCharPtr2一个接一个地指向。但是,*cptr无法更改它们指向的地址处的数据。

\n
int main(void)\n{\n    const char* cptr;\n    char *newCharPtr1 = malloc(sizeof(char));\n    *newCharPtr1 = \'a\';\n    printf("*newCharPtr1: %c\\n", *newCharPtr1);\n    cptr = newCharPtr1;\n    printf("*cptr: %c\\n", *cptr);\n\n    char *newCharPtr2 = malloc(sizeof(char));\n    *newCharPtr2 = \'b\';\n    printf("*newCharPtr2: %c\\n", *newCharPtr2);\n    cptr = newCharPtr2;\n    printf("*cptr: %c\\n", *cptr);\n\n    *cptr = \'c\'; // gcc -> error: assignment of read-only location \xe2\x80\x98*cptr\xe2\x80\x99\n\n    free(newCharPtr1);\n    free(newCharPtr2);\n    \n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

此外,在其他人编写的代码中,您可能会看到const char*char const*可以互换使用。这些是完全相同的。

\n

奇怪的是,有时 C 编译器会被欺骗,如下面的程序所示。

\n
int main(void)\n{\n    const char* sptr;\n    char* newStringPtr1 = malloc(sizeof(char) * 6);\n    strcpy(newStringPtr1, "Hello\\0");\n    printf("*newStringPtr1: %s\\n", newStringPtr1);\n    sptr = newStringPtr1;\n    printf("*sptr: %s\\n", sptr);\n\n    char* newStringPtr2 = malloc(sizeof(char) * 6);\n    strcpy(newStringPtr2, "World\\0");\n    printf("*newStringPtr2: %s\\n", newStringPtr2);\n    sptr = newStringPtr2;\n    printf("*sptr: %s\\n", sptr);\n\n    // gcc -> warning: passing argument 1 of \xe2\x80\x98strcpy\xe2\x80\x99 discards \xe2\x80\x98const\xe2\x80\x99 qualifier from pointer target type\n    strcpy(sptr, "Cruel\\0");\n    // gcc -> /usr/include/string.h:141:39: note: expected \xe2\x80\x98char * restrict\xe2\x80\x99 but argument is of type \xe2\x80\x98const char *\xe2\x80\x99\n    printf("*newStringPtr2: %s\\n", newStringPtr2);\n\n    putchar(\'\\n\');\n    const char* const sptr2 = newStringPtr2;\n    printf("*newStringPtr2: %s\\n", newStringPtr2);\n    printf("*sptr2: %s\\n", sptr2);\n    // gcc -> warning: passing argument 1 of \xe2\x80\x98strcpy\xe2\x80\x99 discards \xe2\x80\x98const\xe2\x80\x99 qualifier from pointer target type\n    strcpy(sptr2, "What?\\0");\n    // gcc -> /usr/include/string.h:141:39: note: expected \xe2\x80\x98char * restrict\xe2\x80\x99 but argument is of type \xe2\x80\x98const char *\xe2\x80\x99\n    printf("*newStringPtr2: %s\\n", newStringPtr2);\n    printf("*sptr2: %s\\n", sptr2);\n\n    free(newStringPtr1);\n    free(newStringPtr2);\n    \n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

上述程序的输出是:

\n
*newStringPtr1: Hello\n*sptr: Hello\n*newStringPtr2: World\n*sptr: World\n*newStringPtr2: Cruel\n\n*newStringPtr2: Cruel\n*sptr2: Cruel\n*newStringPtr2: What?\n*sptr2: What?\n
Run Code Online (Sandbox Code Playgroud)\n

尽管我声明*sptr为 beconst char* sptr*sptr2to be const char* const sptr2,但不知何故strcpy()设法修改了它们指向的地址处的数据。这是因为strcpy()使用指针算术并且增加了另一层间接寻址。添加另一级间接层是没有止境的。这是一个清楚的例子,说明了为什么应该将警告视为错误

\n

要查看如何欺骗 C 编译器的另一个示例,请查看下面 @dbus\ 的答案

\n

C 中字符串数组的表示形式 (char** arr / char* arr[])

\n

在回顾了 C 中字符串的表示之后,现在是时候回顾String ArraysC 中的表示了。

\n

您用类似 的内容声明了一个字符串char* str。字符串数组的声明只是在其后面附加两个方括号:char* str[]。如果你想使用指针,你可以这样做,它char* *str可以读作a char* (str) to another char* (str[0]) which is the first element in a list of char* elements

\n

下面的程序展示了如何使用指针构造字符串数组。请注意,您不能使用数组表示法从堆中获取内存。但是,在使用指针表示法从堆中获取内存后,您可以将其用作数组。这是因为数组没有自己的地址,并且不能指向堆中的另一个地址。您可以通过打印数组的地址和数组中第一个元素的地址来尝试亲自查看。

\n
#define STRING_LENGTH 6\n#define STRING_COUNT 2\n\nint main(void)\n{\n    char* str1 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str1, "Hello\\0");\n\n    char* str2 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str2, "World\\0");\n    \n    char** strArr = calloc(sizeof(char*), STRING_COUNT);\n    strArr[0] = str1;\n    strArr[1] = str2;\n\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n        printf("strArr[%u]: %s\\n", i, strArr[i]);\n    }\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出是:

\n
string[0]: Hello\nstring[1]: World\n\n
Run Code Online (Sandbox Code Playgroud)\n

const 与 char** 的用法

\n

您还记得如何尝试保护 a 的内容吗char*?通过在 const它前面加上:const char*

\n

是什么char**意思?元素数组char*。你能让该数组中的字符串保持不变吗?const是的,您可以通过在元素之前添加一个来做到这一点: const char* *arr

\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define STRING_COUNT 2\n#define STRING_LENGTH 6\n\nint main(void)\n{\n    char* str1 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str1, "Hello\\0");\n\n    char* str2 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str2, "World\\0");\n\n    const char* *strArr = calloc(sizeof(char*), STRING_COUNT);\n    strArr[0] = str1;\n    strArr[1] = str2;\n\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n        printf("string[%u]: %s\\n", i, strArr[i]);\n    }\n\n    strArr[0][0] = \'W\'; // gcc -> error: assignment of read-only location \xe2\x80\x98**strArr\xe2\x80\x99\n\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n       free(strArr[i]);\n    }\n    free(strArr);\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果希望数组中的元素不随其他char*元素改变怎么办?const您在数组名称之前添加另一个关键字,您将得到const char* const *arror const char* const* arror const char* const arr[]。这三个是相同的事情(在访问元素时但不是在从堆中获取内存时,回想一下我之前所说的关于数组表示法的内容)。

\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define STRING_COUNT 2\n#define STRING_LENGTH 6\n\nint main(void)\n{\n    char* str1 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str1, "Hello\\0");\n\n    char* str2 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str2, "World\\0");\n\n    const char* const* strArr = calloc(sizeof(char*), STRING_COUNT);\n    strArr[0] = str1; // gcc -> error: assignment of read-only location \xe2\x80\x98*strArr\xe2\x80\x99\n    strArr[1] = str2; // gcc -> error: assignment of read-only location \xe2\x80\x98*(strArr + 8)\xe2\x80\x99\n\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n        printf("string[%u]: %s\\n", i, strArr[i]);\n    }\n\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n       free(strArr[i]);\n    }\n    free(strArr);\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

上面的示例表明,在获得内存后不能使用 a ,因为立即禁止const char* const* arr将 a 分配给其元素。char*

\n

为了能够初始化一个const char* const* arr,您必须执行如下操作。

\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define STRING_COUNT 2\n#define STRING_LENGTH 6\n\nint main(void)\n{\n    char* str1 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str1, "Hello\\0");\n\n    char* str2 = calloc(sizeof(char), STRING_LENGTH);\n    strcpy(str2, "World\\0");\n\n    const char* *strArrTemp = calloc(sizeof(char*), STRING_COUNT);\n    strArrTemp[0] = str1;\n    strArrTemp[1] = str2;\n\n    const char* const* strArr = strArrTemp;\n\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n        printf("string[%u]: %s\\n", i, strArr[i]);\n    }\n\n    // strArr[1] = str1; // gcc -> error: assignment of read-only location \xe2\x80\x98*(strArr + 8)\xe2\x80\x99\n\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n       free(strArr[i]);\n    }\n    free(strArr);\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出是:

\n
string[0]: Hello\nstring[1]: World\n
Run Code Online (Sandbox Code Playgroud)\n

如何(尝试)保证函数中传递引用参数 (char**) 的安全

\n

数据可以在内存中保存三种不同的位置:只读内存、堆栈内存和堆内存。前面的所有示例都使用堆内存。下一个也是最后一个示例将展示所有三个。作为示例,这是一个很长的程序,但会让您了解函数中参数的保护。

\n

不要关注相同事物的可用性或重复性。

\n
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n\n#define STRING_COUNT 3\n#define STRING_LENGTH 12\n#define SEARCH_STRING "Heap\\0"\n\nunsigned int search0(char* stringArray[], unsigned int stringCount, const char* const StringToSearch)\n{\n//  stringArray[0][0] = \'W\'; // no warning or error\n    strcpy(stringArray[0], "search0\\0"); // no warning or error\n//  stringArray[0] = calloc(sizeof(char), 10); // no warning or error\n//  stringArray = malloc(sizeof(char*) * 10); // no warning or error\n    printf("Inside search0(char* stringArray[], ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], StringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nunsigned int search1(char* const stringArray[], unsigned int stringCount, const char* const StringToSearch)\n{\n//  stringArray[0][0] = \'W\'; // no warning or error\n    strcpy(stringArray[0], "search1\\0"); // no warning or error\n//  stringArray[0] = calloc(sizeof(char), 10); // error\n//  stringArray = malloc(sizeof(char*) * 10); // no warning or error\n\n    printf("Inside search1(char* const stringArray[], ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], StringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nunsigned int search2(const char* stringArray[], unsigned int stringCount, const char* const StringToSearch)\n{\n//  stringArray[0][0] = \'W\'; // error\n    strcpy(stringArray[0], "search2\\0"); // warning\n//  stringArray[0] = calloc(sizeof(char), 10); // no warning or error\n//  stringArray = malloc(sizeof(char*) * 10); // no warning or error\n\n    printf("Inside search2(const char* stringArray[], ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], StringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nunsigned int search3(const char* const stringArray[], unsigned int stringCount, const char* const StringToSearch)\n{\n//  stringArray[0][0] = \'W\'; // error\n    strcpy(stringArray[0], "search3\\0"); // warning\n//  stringArray[0] = calloc(sizeof(char), 10); // error\n//  stringArray = malloc(sizeof(char*) * 10); // no warning or error\n\n    printf("Inside search3(const char* const stringArray[], ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], StringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nunsigned int search4(const char* const* stringArray, unsigned int stringCount, const char* const StringToSearch)\n{\n//  stringArray[0][0] = \'W\'; // error\n    strcpy(stringArray[0], "search4\\0"); // warning\n//  stringArray[0] = calloc(sizeof(char), 10); // error\n//  stringArray = malloc(sizeof(char*) * 10); // no warning or error\n\n    printf("Inside search4(const char* const* stringArray, ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], StringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nunsigned int search5(const char* const* const stringArray[], unsigned int stringCount, const char* const StringToSearch)\n{\n//  stringArray[0][0] = \'W\'; // error\n    strcpy(stringArray[0], "search5\\0"); // warning\n//  stringArray[0] = calloc(sizeof(char), 10); // error\n//  stringArray = malloc(sizeof(char*) * 10); // no warning or error\n\n    printf("Inside search5(const char* const* const stringArray[], ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], StringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nunsigned int search6(const char* const* const stringArray, unsigned int stringCount, const char* const StringToSearch)\n{\n//  stringArray[0][0] = \'W\'; // error\n    strcpy(stringArray[0], "search6\\0"); // warning\n//  stringArray[0] = calloc(sizeof(char), 10); // error\n//  stringArray = malloc(sizeof(char*) * 10); // error\n\n    printf("Inside search6(const char* const* const stringArray, ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        if(strcmp(stringArray[i], StringToSearch) == 0)\n        {\n            return i;\n        }\n    }\n\n    return UINT_MAX;\n}\n\nvoid printStringArray(char* stringArray[], unsigned int stringCount, unsigned int stringPosition)\n{\n    printf("Inside printStringArray(char* stringArray[], ...)\\n");\n    for(unsigned int i = 0; i < stringCount; i++)\n    {\n        printf("stringArray[%u]: %s\\n", i, stringArray[i]);\n    }\n\n    if(stringPosition != UINT_MAX) {\n        printf("%s found at: %u\\n\\n", SEARCH_STRING, stringPosition);\n    } else {\n        printf("%s was not found!\\n", SEARCH_STRING);\n    }\n}\n\n// Don\'t focus on the usability of the program.\n// Or repetition of similar things.\nint main(int argc, char* argv[])\n{\n    char** strArray = calloc(sizeof(char*), STRING_COUNT);\n    for(unsigned int i = 0; i < STRING_COUNT; i++)\n    {\n        strArray[i] = calloc(sizeof(char), STRING_LENGTH);\n    }\n\n    // They are saved in the heap\n    strcpy(strArray[0], "Hello\\0");\n    strcpy(strArray[1], "Heap\\0");\n    strcpy(strArray[2], "World\\0");\n\n    // They are saved in main function stack\n    const char strStack1[15] = "Hello\\0";\n    const char strStack2[15] = "Stack\\0";\n    const char strStack3[15] = "World\\0";\n    const char* const strStackArray[] = { strStack1, strStack2, strStack3 };\n\n    printf("Before search function calls, the strings are like the following!\\n");\n    putchar(\'\\n\');\n\n    printf("strArray[0]: %s\\n", strArray[0]);\n    printf("strArray[1]: %s\\n", strArray[1]);\n    printf("strArray[2]: %s\\n", strArray[2]);\n    putchar(\'\\n\');\n\n    printf("strStack[0]: %s\\n", strStackArray[0]);\n    printf("strStack[1]: %s\\n", strStackArray[1]);\n    printf("strStack[2]: %s\\n", strStackArray[2]);\n    putchar(\'\\n\');\n\n    // Below is the only way of protecting a string from modification.\n    // However, you have to initialize the string in the declaration at compile time.\n    // And it gives a Segmentation Fault at runtime if you try to modify it.\n    // T