分段错误的原因与使用以下 C 代码返回随机值
Reason for Segmentation fault vs returning random values with the following C code
请解释(输出的原因)运行 两段代码的结果。也请解释一下它们的区别。 setArr(int, int)
有两个版本,如下所述...
#include <stdio.h>
void setArr(int, int);
int *arr[10]; // array of 10 int pointers
int main(int argc, char *argv[]) {
int i;
setArr(0, 0);
setArr(1, 100);
setArr(2, 200);
setArr(3, 300);
setArr(4, 400);
for (i = 0; i < 5; i++)
printf("arr[%d]: %d\n", i, *arr[i]); /* should be 0,100, 200,300,400 */
return 0;
}
setArr
的版本
版本 A
void setArr(int index, int v) {
int i = v;
*arr[index] = i;
}
输出: Segmentation fault (core dumped)
版本 B
void setArr(int index, int v) {
int i = v;
arr[index] = &i;
}
输出:
arr[0]: 400
arr[1]: 32748
arr[2]: 32748
arr[3]: 32748
arr[4]: 32748
我假设来自 运行 版本 B 的值只是随机值。
我对指针相当陌生,我了解 Java,所以请尽可能以初学者友好的方式对其进行解释 :)
版本 A 说 "the contents of an undefined pointer equals i" - 未定义的行为 = 崩溃。基本上你正在尝试写入内存中的某个未知位置。
版本 B 说 "Some pointer = some address" - 仍然是未定义的行为,因为 &i
超出了范围,但它仍然是一个地址,所以它 "kind of works"。在这里,您正在写入 "good" 个内存位置,但正在读取错误的内存位置。
您遇到了很多未定义的行为场景,但我会解释可能发生的情况。
arr
是一个包含 10 个整数指针的数组。
int * arr[10]; // array of 10 int pointers
当声明为全局变量时,所有这些指针都将是 zero-initialized - 因此,它是一个包含 10 个 NULL 指针的数组。
因此,版本 A 中的这一行取消了对地址 arr[index]
:
的引用
* arr[index] = i;
实际上是在说:
*(NULL) = i;
那肯定会一直崩溃。
在版本 B 中,您将其设置为:
int i = v;
arr[index] = &i;
所以现在您正确地将指针分配给数组中的槽。然而,该地址被分配给局部堆栈变量 i
,一旦函数 returns,它就超出范围。因此,当您在该地址打印值时,它肯定会被写在堆栈顶部的其他调用破坏。 (或者从技术上讲,"undefined behavior" 访问超出范围的堆栈变量的内存地址。)
更好:
void setArr (int index, int v){
arr[index] = malloc(sizeof(int));
*arr[index] = v;
}
上面为您要将该值复制到的地址分配了内存。如何释放该内存,您需要自己解决。
或者:
只需将 arr
声明为整数数组而不是指针:
int arr[10];
void setArr (int index, int v){
arr[index] = v;
}
然后在 arr
.
上没有 *
尊重的情况下正常打印
printf("arr[%d]: %d\n", i, arr[i]);
在第一种情况下,您已将 "array of pointers" 定义为整数。它们不是整数指针。在向它们存储任何值之前,您必须分配内存(最好使用 melloc/calloc 函数),或者您可以像这样定义整数数组:
int (*a)[10]
以下 link 可能会让您对此有所了解:Difference between *ptr[10] and (*ptr)[10]
在第二种情况下,您将整数地址保存到整数指针中,这没问题,但是 int i
是函数 setArr()
的局部变量。因此,每次函数 setArr()
退出时,都会取消引用 int i
的值。因此,您将获得第二种情况的未定义行为。您可以使用 static int i
或使用全局变量(不是首选)或使用指向整数赋值的指针。
请解释(输出的原因)运行 两段代码的结果。也请解释一下它们的区别。 setArr(int, int)
有两个版本,如下所述...
#include <stdio.h>
void setArr(int, int);
int *arr[10]; // array of 10 int pointers
int main(int argc, char *argv[]) {
int i;
setArr(0, 0);
setArr(1, 100);
setArr(2, 200);
setArr(3, 300);
setArr(4, 400);
for (i = 0; i < 5; i++)
printf("arr[%d]: %d\n", i, *arr[i]); /* should be 0,100, 200,300,400 */
return 0;
}
setArr
版本 A
void setArr(int index, int v) {
int i = v;
*arr[index] = i;
}
输出: Segmentation fault (core dumped)
版本 B
void setArr(int index, int v) {
int i = v;
arr[index] = &i;
}
输出:
arr[0]: 400 arr[1]: 32748 arr[2]: 32748 arr[3]: 32748 arr[4]: 32748
我假设来自 运行 版本 B 的值只是随机值。
我对指针相当陌生,我了解 Java,所以请尽可能以初学者友好的方式对其进行解释 :)
版本 A 说 "the contents of an undefined pointer equals i" - 未定义的行为 = 崩溃。基本上你正在尝试写入内存中的某个未知位置。
版本 B 说 "Some pointer = some address" - 仍然是未定义的行为,因为 &i
超出了范围,但它仍然是一个地址,所以它 "kind of works"。在这里,您正在写入 "good" 个内存位置,但正在读取错误的内存位置。
您遇到了很多未定义的行为场景,但我会解释可能发生的情况。
arr
是一个包含 10 个整数指针的数组。
int * arr[10]; // array of 10 int pointers
当声明为全局变量时,所有这些指针都将是 zero-initialized - 因此,它是一个包含 10 个 NULL 指针的数组。
因此,版本 A 中的这一行取消了对地址 arr[index]
:
* arr[index] = i;
实际上是在说:
*(NULL) = i;
那肯定会一直崩溃。
在版本 B 中,您将其设置为:
int i = v;
arr[index] = &i;
所以现在您正确地将指针分配给数组中的槽。然而,该地址被分配给局部堆栈变量 i
,一旦函数 returns,它就超出范围。因此,当您在该地址打印值时,它肯定会被写在堆栈顶部的其他调用破坏。 (或者从技术上讲,"undefined behavior" 访问超出范围的堆栈变量的内存地址。)
更好:
void setArr (int index, int v){
arr[index] = malloc(sizeof(int));
*arr[index] = v;
}
上面为您要将该值复制到的地址分配了内存。如何释放该内存,您需要自己解决。
或者:
只需将 arr
声明为整数数组而不是指针:
int arr[10];
void setArr (int index, int v){
arr[index] = v;
}
然后在 arr
.
*
尊重的情况下正常打印
printf("arr[%d]: %d\n", i, arr[i]);
在第一种情况下,您已将 "array of pointers" 定义为整数。它们不是整数指针。在向它们存储任何值之前,您必须分配内存(最好使用 melloc/calloc 函数),或者您可以像这样定义整数数组:
int (*a)[10]
以下 link 可能会让您对此有所了解:Difference between *ptr[10] and (*ptr)[10]
在第二种情况下,您将整数地址保存到整数指针中,这没问题,但是 int i
是函数 setArr()
的局部变量。因此,每次函数 setArr()
退出时,都会取消引用 int i
的值。因此,您将获得第二种情况的未定义行为。您可以使用 static int i
或使用全局变量(不是首选)或使用指向整数赋值的指针。