本地指针数组的问题

时间:2018-02-03 22:58:31

标签: c arrays function pointers

我已经做了一些挖掘,但无法找到解决方案。在下面的代码中,当我将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数组(?)

的指针 如果我错了,请纠正我

1 个答案:

答案 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 + indexarray + 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*(底部)。基本上是顶级代表 是arraymain所拥有的内容。最底层的就是你所拥有的 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);

释放记忆。