C函数中双指针和单指针有什么区别
What is the difference between double pointers and single pointer in C functions
我是 C 编程语言的新手,开始弄乱指针和为对象分配内存。我想制作一个简单的程序,它可以从用户那里读取 (x) 个元素,然后使用函数简单地将它们打印出来。
这是我一开始的初始代码。代码可以正确读取用户输入,但在显示主函数中的元素时会给出错误的输出并崩溃。
int main() {
int *myArr;
int myArrSize;
getInputArr(&myArrSize, &myArr);
for (int i = 0; i < myArrSize; i++) {
printf("Element No.%i: %i\n", i, myArr[i]);
}
free(myArr);
return 0;
}
void getInputArr(int *arrSize, int *arr) {
printf("Please Enter Length of Array: \n");
scanf("%i", arrSize);
arr = (int *) malloc(*arrSize * sizeof(int));
printf("Enter %i Numbers!\n", *arrSize);
for (int i = 0; i < *arrSize; i++) {
scanf("%i", &arr[i]);
}
}
经过折腾,我终于用双指针让它工作了,但我不确定它是如何完全工作的,有人能解释一下为什么下面的代码表现得像预期的那样吗?
int main() {
int *myArr;
int myArrSize;
getInputArr(&myArrSize, &myArr);
for (int i = 0; i < myArrSize; i++) {
printf("Element No.%i: %i\n", i, myArr[i]);
}
free(myArr);
return 0;
}
void getInputArr(int *arrSize, int **myArr) {
printf("Please Enter Length of Array: \n");
scanf("%i", arrSize);
*myArr = (int *) malloc(*arrSize * sizeof(int));
printf("Enter %i Numbers!\n", *arrSize);
for (int i = 0; i < *arrSize; i++) {
scanf("%i", &((*myArr)[i]));
}
}
您的实施中有几件令人惊讶的事情,但最终它们都是有道理的,而且确实必须存在它们才能使该实施正常工作。
- 你最终希望
main
中的int *myArr
模拟一个int
的数组,但在getInputArr
中你使用“双指针”引用它int **myArr
.但这是有道理的,因为任何时候你想 return 像这样“通过引用”从函数中得到一些东西,你需要使用一个指针——一个额外的指针。要通过引用 return 一个 int,您将使用 int *
。但是要通过引用 return 和 int *
,您需要一个 int **
。您(正确)在 main
中调用 getInputArr(&myArrSize, &myArr)
的事实表明 getInputArr
的第二个参数将是 int **
.
- 在 getInputArr 中,当您调用
scanf
时,您 而不是 在您传递给 scanf
的参数旁边有一个 &
%d
读入。这是非常不寻常的,但在这种情况下它是绝对正确的,因为 arrSize
已经是一个指针。
- 然后你有
*myArr = (int *) malloc(*arrSize * sizeof(int))
。这是我在您的初始(非工作)实现中发现的第一个错误。在getInputArr
中,myArr
是指向你要设置的指针的指针。所以*myArr
就是你要设置的指针。
- 最后,你有 jawbreaker 调用
scanf("%i", &((*myArr)[i]));
。这看起来很丑陋,可能有更简单的方法来编写它,但它是正确的。让我们分解一下。同样,myArr
是指向您要使用的指针的指针。所以 *myArr
是您要使用的指针。因此 (*myArr)[i]
是您要使用的模拟数组(由指针指向)的一个元素。你需要明确的括号,因为如果你写 *myArr[i]
这意味着,“获取 myArr
指向的第 i
个元素,将其解释为指针,并获取内容。”但是你想要的(并且,在括号中,你有)是“接受 myArr
,将其解释为指针,接受它指向的东西,即 *myArr
,并解释 that作为指针,最后取它(第二个指针)指向的第i
个元素。"
您有多个级别的指针让您感到困惑。但是,如果您正在处理的动态分配的数组存在于结构中怎么办?然后我们只需要处理该结构上的指针传递(“引用”)语义。
考虑以下内容。看评论解释。
/* Basic stuff. */
#include <stdio.h>
#include <stdlib.h>
/* Here's our struct.
* It contains the size of the array,
* and the pointer to the memory allocated for the array.
*/
typedef struct dyn_int_array {
size_t size;
int * array;
} dyn_int_array_t;
/* Forward declarations for a function which creates and
* returns our dynamic_int_array struct.
*/
dyn_int_array_t * create_dyn_int_array();
/* ... and here's where you see that we don't want to
* pass the struct by value, but rather effectively by
* reference by passing a pointer to it.
*/
void scan_into_dyn_int_array(dyn_int_array_t * da);
int main(void) {
dyn_int_array_t * da = create_dyn_int_array();
/* I never bothered to free up the allocated memory,
* because it's not really critical for demonstration here.
*/
}
这些函数的实现在下面,但对于这个演示来说并不是真正的关键,因为您希望看到指针的引用传递,而不必 直接 担心两级指针间接寻址或感到困惑。
dyn_int_array_t * create_dyn_int_array() {
dyn_int_array_t * result = malloc(sizeof(dyn_int_array_t));
fprintf(stdout, "Input an array size: ");
fscanf(stdin, "%zd", &(result->size));
result->array = malloc(sizeof(int) * result->size);
/* Because "da" is already a pointer to dye_int_array_t
* there's no need to get its address.
*/
scan_into_dyn_int_array(result);
return result;
}
void scan_into_dyn_int_array(dyn_int_array_t * da) {
for (int i = 0; i < da->size; i++) {
/* We do have to pass the address of the current
* element of the array to fscanf.
*/
fscanf(stdin, "%d", &(da->array[i]));
}
}
我是 C 编程语言的新手,开始弄乱指针和为对象分配内存。我想制作一个简单的程序,它可以从用户那里读取 (x) 个元素,然后使用函数简单地将它们打印出来。
这是我一开始的初始代码。代码可以正确读取用户输入,但在显示主函数中的元素时会给出错误的输出并崩溃。
int main() {
int *myArr;
int myArrSize;
getInputArr(&myArrSize, &myArr);
for (int i = 0; i < myArrSize; i++) {
printf("Element No.%i: %i\n", i, myArr[i]);
}
free(myArr);
return 0;
}
void getInputArr(int *arrSize, int *arr) {
printf("Please Enter Length of Array: \n");
scanf("%i", arrSize);
arr = (int *) malloc(*arrSize * sizeof(int));
printf("Enter %i Numbers!\n", *arrSize);
for (int i = 0; i < *arrSize; i++) {
scanf("%i", &arr[i]);
}
}
经过折腾,我终于用双指针让它工作了,但我不确定它是如何完全工作的,有人能解释一下为什么下面的代码表现得像预期的那样吗?
int main() {
int *myArr;
int myArrSize;
getInputArr(&myArrSize, &myArr);
for (int i = 0; i < myArrSize; i++) {
printf("Element No.%i: %i\n", i, myArr[i]);
}
free(myArr);
return 0;
}
void getInputArr(int *arrSize, int **myArr) {
printf("Please Enter Length of Array: \n");
scanf("%i", arrSize);
*myArr = (int *) malloc(*arrSize * sizeof(int));
printf("Enter %i Numbers!\n", *arrSize);
for (int i = 0; i < *arrSize; i++) {
scanf("%i", &((*myArr)[i]));
}
}
您的实施中有几件令人惊讶的事情,但最终它们都是有道理的,而且确实必须存在它们才能使该实施正常工作。
- 你最终希望
main
中的int *myArr
模拟一个int
的数组,但在getInputArr
中你使用“双指针”引用它int **myArr
.但这是有道理的,因为任何时候你想 return 像这样“通过引用”从函数中得到一些东西,你需要使用一个指针——一个额外的指针。要通过引用 return 一个 int,您将使用int *
。但是要通过引用 return 和int *
,您需要一个int **
。您(正确)在main
中调用getInputArr(&myArrSize, &myArr)
的事实表明getInputArr
的第二个参数将是int **
. - 在 getInputArr 中,当您调用
scanf
时,您 而不是 在您传递给scanf
的参数旁边有一个&
%d
读入。这是非常不寻常的,但在这种情况下它是绝对正确的,因为arrSize
已经是一个指针。 - 然后你有
*myArr = (int *) malloc(*arrSize * sizeof(int))
。这是我在您的初始(非工作)实现中发现的第一个错误。在getInputArr
中,myArr
是指向你要设置的指针的指针。所以*myArr
就是你要设置的指针。 - 最后,你有 jawbreaker 调用
scanf("%i", &((*myArr)[i]));
。这看起来很丑陋,可能有更简单的方法来编写它,但它是正确的。让我们分解一下。同样,myArr
是指向您要使用的指针的指针。所以*myArr
是您要使用的指针。因此(*myArr)[i]
是您要使用的模拟数组(由指针指向)的一个元素。你需要明确的括号,因为如果你写*myArr[i]
这意味着,“获取myArr
指向的第i
个元素,将其解释为指针,并获取内容。”但是你想要的(并且,在括号中,你有)是“接受myArr
,将其解释为指针,接受它指向的东西,即*myArr
,并解释 that作为指针,最后取它(第二个指针)指向的第i
个元素。"
您有多个级别的指针让您感到困惑。但是,如果您正在处理的动态分配的数组存在于结构中怎么办?然后我们只需要处理该结构上的指针传递(“引用”)语义。
考虑以下内容。看评论解释。
/* Basic stuff. */
#include <stdio.h>
#include <stdlib.h>
/* Here's our struct.
* It contains the size of the array,
* and the pointer to the memory allocated for the array.
*/
typedef struct dyn_int_array {
size_t size;
int * array;
} dyn_int_array_t;
/* Forward declarations for a function which creates and
* returns our dynamic_int_array struct.
*/
dyn_int_array_t * create_dyn_int_array();
/* ... and here's where you see that we don't want to
* pass the struct by value, but rather effectively by
* reference by passing a pointer to it.
*/
void scan_into_dyn_int_array(dyn_int_array_t * da);
int main(void) {
dyn_int_array_t * da = create_dyn_int_array();
/* I never bothered to free up the allocated memory,
* because it's not really critical for demonstration here.
*/
}
这些函数的实现在下面,但对于这个演示来说并不是真正的关键,因为您希望看到指针的引用传递,而不必 直接 担心两级指针间接寻址或感到困惑。
dyn_int_array_t * create_dyn_int_array() {
dyn_int_array_t * result = malloc(sizeof(dyn_int_array_t));
fprintf(stdout, "Input an array size: ");
fscanf(stdin, "%zd", &(result->size));
result->array = malloc(sizeof(int) * result->size);
/* Because "da" is already a pointer to dye_int_array_t
* there's no need to get its address.
*/
scan_into_dyn_int_array(result);
return result;
}
void scan_into_dyn_int_array(dyn_int_array_t * da) {
for (int i = 0; i < da->size; i++) {
/* We do have to pass the address of the current
* element of the array to fscanf.
*/
fscanf(stdin, "%d", &(da->array[i]));
}
}