我已经做了一些挖掘,但无法找到解决方案。在下面的代码中,当我将float **array
声明为全局变量时,我的程序按预期运行。但是我试图在main()
中声明它并将其传递给函数,当我尝试编译时,我遇到了一些令人讨厌的错误。
以下示例运行:
lab2.c: In function ‘NumOfVal’:
lab2.c:116: error: incompatible types when assigning to type ‘float’ from type ‘void *’
lab2.c:118: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:119: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:124: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:125: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘calculateSum’:
lab2.c:137: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:140: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘calculateAvg’:
lab2.c:150: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:153: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘findMax’:
lab2.c:162: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:165: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:166: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘findMin’:
lab2.c:174: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:175: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:177: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:178: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c: In function ‘printVal’:
lab2.c:187: error: invalid type argument of ‘unary *’ (have ‘float’)
lab2.c:189: error: invalid type argument of ‘unary *’ (have ‘float’)
现在我意识到我的“计算功能”的错误都是一样的,但第116行的第一个错误是不同的。我不明白为什么一旦我在main()
本地声明我的指针,它就会给我所有这些问题。我必须使用指针算法,不要看声明如何:
*(array + index) = malloc();
不再有效.. 为什么本地声明会更改分配内存和读取/写入数组的语法?
以下代码:我不包括一些节省空间的“计算功能”
/* Function declarations */
void printVal();
void userChoice();
void calculateSum();
void calculateAvg();
void findMin();
void findMax();
int main(){
float **array;
int numData;
/*get number of datasets */
numData = NumOfSet();
printf("%d\n",numData);
array = malloc(numData * sizeof(float*));
if(array != 0){
/* get # of values per dataset and enter those values */
NumOfVal(numData, array);
}
else{
printf("Memory Allocation Failed");
}
userChoice();
}
void userChoice(){
int flag = 1;
int setChoice;
int opChoice;
while(1){
if(flag == 0)
break;
printf("Which dataset would you like to perform operations on?: \n");
scanf("%d", &setChoice);
printf("Which operation would you like to perform on dataset #%d\n", setChoice);
printf("1. Calculate sum of all the values\n");
printf("2. Calculate average of all the values\n");
printf("3. Find the minimum value\n");
printf("4. Find the maximum value\n");
printf("5. Print values in dataset\n");
printf("6. Exit the program\n");
scanf("%d", &opChoice);
/* Switch statement which makes function calls to perform whatever the user specified */
switch(opChoice){
case 1:
calculateSum(setChoice);
break;
case 2:
calculateAvg(setChoice);
break;
case 3:
findMin(setChoice);
break;
case 4:
findMax(setChoice);
break;
case 5:
printVal(setChoice);
break;
case 6:
flag = 0;
printf("Thanks for playing!\n");
printf("%d", flag);
}
}
}
int NumOfSet(){
int numData;
printf("Enter number of Datasets: \n");
scanf("%d",&numData);
return(numData);
}
/* for each data set declare size and input float values */
int NumOfVal(int data, float *array){
int index; /* counters */
int array_index;
int copy;
float size;
float val;
for(index = 0; index < data;index++){
printf("Enter size of dataset %d:\n", index);
scanf("%f", &size);
copy = size;
printf("Size = %d\n", (int) size);
printf("Array #: %d\n", index);
/* malloc() for row */
/* array[index] */
*(array + index) = malloc(size * sizeof(float));
/*array[index][0] */
*(*(array + index) + 0) = size;
printf("%f\n", *(*(array + index) + 0));
/* loop for entering float values */
for(array_index = 1; array_index <= copy; array_index++){
printf("Enter each float value:");
scanf("%f", &val);
*(*(array + index) + array_index) = val;
printf("%f\n", *(*(array + index) + array_index));
printf("count: %d\n",array_index);
printf("size: %d\n",copy);
}
}
}
void calculateSum(int setChoice, float *array){
int i;
int first = *(*(array + setChoice-1) + 0);
float sum = 0;
for(i = 1; i <= first; i++){
sum += *(*(array + setChoice-1) + i);
}
printf("The sum of the values is: %.3f\n", sum);
}
P.S。当然,当我将数组声明为全局时,我没有将数组作为这些函数的参数。
所以我似乎在float
中声明指向float **array
main()
的指针。我需要float **array
作为我的函数的参数,而不仅仅是float *array
。
**array
- &gt;指向float
数组(?)
*array
- &gt;只是指向单个float
数组(?)
答案 0 :(得分:0)
首先,您必须了解指针是什么。指针是变量的
存储地址。它可能是另一个变量的地址,也可能是
启动你从动态分配内存中得到的内存块
malloc
&amp;朋友或阵列的开始。
的指针
*array
- &gt;只是指向单个float
数组(?)
不一定。
让我们来看看:
float *array;
首先,忘记变量的名称,真正重要的是
变量的类型。在这种情况下,您已获得指向float
的指针。
可能指向单个浮点变量
float n = 8.7;
float *array = &n;
但可能指向float
s(又名数组)序列的开头:
float na[] = { 1.1, 2.2, 3.3, 4.4 };
float *array = na;
//or
float *array = na + 2;
哪一个(指向单个对象vs指向一个对象数组)是
正确的一个取决于上下文。该函数的文档将告诉我们
你期待的是什么。 那是重要的,而不是变量名。如果
变量名是array
,它可能没有指向数组,那么名称就是
误导,实际上是一个选择不当的名字。
列表的指针
**array
- &gt;指向float
数组(?)
同样,不一定。
让我们更进一步。双指针
float **array;
是指向float
的另一个指针的指针。再一次,忘了
变量的名称,上下文很重要。它可能指向一个指针
指向一个变量:
float n = 8.7;
float *array = &n;
float **p2arr = &array;
或者它可能指向指向数组开头的指针
float na[] = { 1.1, 2.2, 3.3, 4.4 };
float *array = na;
float **p2arr = &array;
// *p2arr[0] == 1.1
// *(p2arr[0] + 1) == 2.2
// *(p2arr[0] + 2) == 3.3
或者它可能指向指向单个float
值的指针数组:
float a=1.1, b=2.2, c=3.3;
float **ppa = calloc(3, sizeof *ppa);
ppa[0] = &a;
ppa[1] = &b;
ppa[2] = &b;
或者如果指向float
数组的指针,它可能指向数组
值:
float **ppa = calloc(3, sizeof *ppa);
ppa[0] = calloc(5, sizeof *ppa[0]);
ppa[1] = calloc(2, sizeof *ppa[1]);
ppa[2] = calloc(9, sizeof *ppa[2]);
ppa[0][0] = 1.1;
ppa[0][1] = 2.2;
ppa[1][0] = 10.8;
ppa[2][5] = 11.1;
上下文很重要,如果您使用的函数有float **arg
参数,函数文档将告诉你它会从中得到什么
一个指针。如果你正在创建一个功能,你决定上下文,
因为你知道你在做什么。
关于你的代码。据我所见,float **array;
中的main
分配
指针数组的内存。在这种情况下,我建议使用calloc
相反,因为calloc
将分配的内存设置为0.它进行初始化
并且即使后续调用,也可以更容易地释放整个块
malloc
/ realloc
/ calloc
失败。
array = calloc(numData, sizeof *array);
另请注意,我未在此使用sizeof(float*)
,而是使用sizeof *array
。
前者并不是错误的,但更容易犯错误就像遗忘
*
或添加超过需要的,特别是在何时
处理双指针。然而,后者将始终返回正确的
尺寸,无论何种类型。
现在您已经分配并初始化了数组。所有指针array[0]
,
array[1]
等已初始化并指向NULL
。你打电话
NumOfVal(numData, array);
以及那些出错的地方。
让我们看看函数的签名:
int NumOfVal(int data, float *array);
它需要一个单指针,因此不好,你不能传递双精度 指针。由于您自己编写函数,因此可以更改 功能并设置自己的上下文。
在修复此功能之前,让我们看一下NumOfVal
中的这一行:
*(array + index) = malloc(size * sizeof(float));
再次在这里,我建议使用calloc
。第二,让我们来看看:
*(array + index)
。它与执行array[index]
相同,并会返回给您
一个float
。你基本上是这样做的:
float f = malloc(sizeof * sizeof(float));
这是错误的,因为malloc
返回void
指针,你无法设置
float
指向void
指针。
但是你的思路也错了,因为array
变量在
main
是双指针,内存布局不同。为什么呢?
我将更改变量的名称,以明确我所指的变量。
*(array_main + index)
与执行array_main[index]
相同。它会回报你
指向float
的指针。当您将array_main
传递给NumOfVal
时,您就是现在
像对待一个指针一样对待它。 float
的大小和a的大小
指向float
的指针可能不一样,因此array_main + index
和array + index
会返回给您
不同的记忆位置。实际上它会返回一个内存位置
保存指针,而不是float
保存的位置,因此您正在销毁指针
指针保存在array_main
。
pfs = sizeof(float*)
fs = sizeof(float)
real address base base+pfs base+2*pfs base+3*pfs
pointer arithmetic base base+1 base+2 base+3
+---------+----------+----------+
| float* | float * | float * |
+---------+----------+----------+
real address base base+fs base+2*fs base+3*fs
pointer arithmetic base base+1 base+2 base+3
+-----------+-----------+-----------+
| float | float | float |
+-----------+-----------+-----------+
上图显示了相同的内存地址base
float**
(顶部)并被视为float*
(底部)。基本上是顶级代表
是array
中main
所拥有的内容。最底层的就是你所拥有的
array
中的NumOfVal
。你看到指针算术没有排列,所以你
访问不正确的内存位置,并产生未定义
行为。
如何解决?像这样修复NumOfVal
:
int NumOfVal(int data, float **array) {
int index; /* counters */
int array_index;
int copy;
float size;
float val;
for(index = 0; index < data;index++){
printf("Enter size of dataset %d:\n", index);
scanf("%f", &size);
copy = size;
printf("Size = %d\n", (int) size);
printf("Array #: %d\n", index);
/* malloc() for row */
/* array[index] */
array[index] = calloc(size + 1, sizeof *index);
array[index][0] = size;
我看到你想使用第一个元素来保存大小。这是一个很好的策略,
但是你需要再分配一个元素,否则你for
循环会溢出。
您在calculateSum
中遇到了同样的问题,同样的问题:
void calculateSum(int setChoice, float **array){
int i;
int first = array[setChoice-1][0];
float sum = 0;
for(i = 1; i <= first; i++){
sum += array[setChoice - 1][i];
}
printf("The sum of the values is: %.3f\n", sum);
}
永远不要忘记检查malloc
&amp;的返回值朋友们,如果他们回来了
NULL
,您无法访问该内存。还写一个释放的函数
记忆。这里calloc
会派上用场,因为free(NULL);
是合法的。
void free_array(int size, float **array)
{
if(array == NULL)
return;
for(int i = 0; i < size; ++i)
free(array[i]);
free(array);
}
在你的NumOfVal
功能中,你应该这样做:
array[index] = calloc(size + 1, sizeof *index);
if(array[index] == NULL)
{
// error handling
return 0;
}
此外,您忘记在NumOfVal
中返回值。如果你的功能不是
无论如何要返回一个值,将其声明为void
。
完成计算后,现在在main
:
free_array(numData, array);
释放记忆。