在函数中使用字符串数组

3

我正在练习字符串数组,但好像不理解它如何工作,有人能向我解释一下正确的编写代码方式吗?

代码目标:将两个字符串赋值给一个字符串数组,并使用函数打印它们。

错误:编译器没有发现任何错误,但是我在终端中没有得到任何输出。

#include <stdio.h>

#define MAX 100

void function(char **);

int main()
{    
    char *a[MAX]; /*array of max 100 strings*/
    a[0] = "test0";
    function(&a[MAX]);    
    return 0;
}

void function(char *a[MAX])
{    
    a[1] = "test1";
    printf("%s",*a[1]);
    printf("%s",*a[0]);
}

你的意思是在第一个打印语句中使用 "%d" 吗?出了什么问题? - doctorlove
不,这只是一个小错误,不是主要问题,我已经更新了问题。 - Pinguiz
你的具体问题是什么?-- 你把指针数组的最后一个元素之后的指针传递给函数。我确定这不是你想要的。 - the busybee
2
你正在将函数传递给a最后一个元素之后的地址,这也是错误的类型。你应该在这里得到一堆警告。 - Eugene Sh.
抱歉如果问题没有表达清楚,我的目的是打印出a[1]和a[0]的值,但是我遇到了一些错误,我将编辑问题并添加这些错误信息。 - Pinguiz
如果您正在寻求特定错误的帮助,请在您的问题中包含这些错误。 - Caleb
3个回答

1
编译器没有发现任何错误,但是在终端中根本没有输出。这是因为你传递的地址不是函数所期望的内容。
function(&a[MAX]);

你正在传递数组 a 中索引为 MAX 的项的地址,但是你的函数将其解释为整个数组的地址。你应该改为写成:

function(a)

看起来您混淆了参数声明的方式和在函数调用中使用它的方式。当您声明一个函数时,必须指定参数的类型,因此您可以使用例如char *s[]来表示字符指针数组。但是在调用函数时,编译器已经知道函数需要的类型,所以您只需要传递与声明类型匹配的变量即可。在这种情况下,像a[MAX]这样的方括号被解释为选择数组的一个元素的下标。
此外,作为一种风格,function是一个糟糕的函数名称。我知道这只是一个小型测试程序,所以没关系,但请尝试养成给事物命名具有描述性的习惯。
还有:
printf("%s",*a[1]);
printf("%s",*a[0]);

在这里,您正在访问索引为1的项目,但是您还没有在那里存储任何内容。这不是一个好计划。要么删除第一行,要么更改代码以在索引1中存储某些内容。

此外,您不需要取消引用元素。数组中的每个元素都是字符数组,printf()将期望char *类型的值,这就是每个a[n]将成为的内容。所以只需使用:

printf("%s", a[1]);
printf("%s", a[0]);

将数组称为function(a),是否将整个数组传递给函数的所有数组? 附:我确实分配了a[1],但我尝试在函数内部执行它以测试它的工作原理。 - Pinguiz
1
抱歉,我忘记提到 a[1] 了。无论如何,是的,将数组称为 a 提供了数组的值,实际上只是第一个元素(索引为0的元素)的地址。出于同样的原因,您的 printf() 语句应该将字符串称为例如 a[0],而不是 *a[0]*a[0] 是数组中第一个字符串的第一个字符。请注意,我刚才添加了这一点的编辑。 - Caleb
谢谢,看起来可以工作!如果我想在函数内访问字符串a[0]的第三个字母怎么办? - Pinguiz
1
有更短的方法,但在学习时最好保持简单:char *s = a [0]; char c = s [2]; - Caleb

1

你似乎对你正在使用的指针及其正确类型存在一些困惑。希望下面的程序可以澄清一些事情。注释中有解释:

#include <stdio.h>

#define MAX 100

void function(char* (*aPtr)[MAX])
{
    // Since aPtr is a pointer, we need to derefecence it with * before assigning
    // string literals
    (*aPtr)[1] = "test1";
    printf("In function\n");
    printf("%s\n",(*aPtr)[0]);
    printf("%s\n\n",(*aPtr)[1]);
}

void function2(char** a)
{
    // Remember, * and [] can both be used to dereference in C
    // This is equivalent to *(a+2) = "test2";
    a[2] = "test2";
    printf("In function2\n");
    printf("%s\n",a[0]);
    printf("%s\n",a[1]);
    printf("%s\n\n",a[2]);
}

int main(void)
{
    // This is an array of MAX char pointers. Just on declaration, each pointer in the array
    // points to nothing. You can point them to a string literal (as you have done), or use
    // something like malloc to allocate space for each one
    char *a[MAX];
    // This is a pointer to an array of MAX char pointers. This is the type you're trying to
    // pass to `function`, which is not used correctly
    char* (*aPtr)[MAX] = &a;
    // I've included these prints so you can see the difference between `a` and `aPtr` via pointer
    // arithmetic. In this printf, `a` "decays" to a pointer to the first element in the array.
    // The first element of the array is a `char*`, so a pointer to that is a `char**`, so
    // that's what `a` is in this context, pointing to a[0]. What the actual address is here isn't
    // important, just think of this as offset 0
    printf("pointer to first element      = %p\n", (void*)a);
    // This is the explicit address of the first element in the array. Notice how it is
    // identical to the address of the array above.
    printf("address of first element      = %p\n", ((void*)&(a[0])));
    // This illustrates the "decay" concept again. `a` decays to a `char**`, and +1 on that
    // shows pointer arithmetic. On this architecture, pointers are 8 bytes, so a+1
    // advances the pointer by 8 bytes, which points to the 2nd element in the array.
    // This output will be the offset +8
    printf("pointer to second element     = %p\n", (void*)(a+1));
    // This shows the address of aPtr. Remember, this is a pointer to an array of char
    // pointers 100 large. This base address is also the address of where the array starts,
    // so it will be identical to offset
    printf("address of array              = %p\n", (void*)aPtr);
    // This is where the different pointer types are illustrated. Since char pointers are 8
    // bytes on this architecture, an array of 100 of them is 8*100 = 800 bytes. So aPtr+1
    // here performs pointer arithmetic on that type, meaning it advances the pointer 800
    // bytes. The print out here will be offset +800.
    printf("pointer to next array element = %p\n\n", (void*)(aPtr+1));

    // assign a[0] to point to the string literal "test0"
    a[0] = "test0";

    // This is what you're trying to do (but doing incorrectly) with your function call.
    // This passes the address of `a`, a pointer to an array of char pointers 100 large.
    // This is identical to passing `&a`, the address of `a`.
    function(aPtr);
    // `a` in this context "decays" to a pointer to its first element. Its first element is
    // `char*`, so here `a` is `char**`. And this is the signature you'll find in function2
    function2(a);

    // print out in main to show all the assignments were made
    printf("in main\n");
    printf("%s\n",a[0]);
    printf("%s\n",a[1]);
    printf("%s\n",a[2]);

    return 0;
}

Demo


1
哇!多么详尽的答案,谢谢!我还有一个疑问,如果在函数2中我想要a[0]的第三个字母怎么办? - Pinguiz
1
@Pinguiz 我总是需要考虑数组指针,我写出来的东西对我和你都有帮助。第一个字符串的第三个字母是 a[0][2]。在 function2 中,a 是一个 char**,所以 a[0] 是第一个 char*,而 a[0][2] 是从第一个 char* 开始偏移的第三个 char。你可以去 Demo 链接并在那个沙盒中玩耍,不要忘记 "%c" 是打印 char 的格式说明符。 - yano

-1
你需要传递数组的指针,即:
function(a)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接