我正在学习c语言中的指针。为了详细说明,我正在编写一个数组程序。我想要实现的是,如果数组的大小为0(最初)创建一个动态数组,使用大小为2的malloc,然后在初始位置添加元素。
此外,当添加更多元素时,如果总元素==数组的大小,则使用malloc创建一个新数组,其大小是先前大小的两倍。我创建了一个临时数组,从前一个数组复制元素,然后在最后添加新元素。问题是,当我试图打印元素时,我得到的是最后一个元素的地址,而不是元素的地址。
这是完整的代码。
#include<stdio.h>
#include<stdlib.h>
void display(int *arr, int *total_elements)
{
if(*total_elements==0){
printf("No elements present in arrayn");
return;
}
else
{
for(int i=0;i< *total_elements;i++){
printf("%dt",*(arr+i));
}
}
}
void push(int *arr, int *size, int ele, int *total_elements)
{
if(*size==0)
{
*arr = (int*)malloc(2*sizeof(int));
arr[*size] = ele;
*total_elements = *total_elements + 1;
*size = *size + 2;
return;
}
else if(*size>*total_elements)
{
arr[*total_elements] = ele;
*total_elements = *total_elements + 1;
return;
}
else if(*size==*total_elements)
{
int *temp,i;
temp = (int*)malloc((*(size)*2)*sizeof(int));
for(i=0;i < *size;i++)
{
temp[i] = *(arr+i);
}
temp[i]=ele;
arr = temp;
*size = (*size)*2;
*total_elements = *total_elements + 1;
for(int i=0;i< *total_elements;i++){
printf("%dt",*(arr+i));
}
}
}
void pop()
{
}
void main()
{
int select=0;
int *arr, size=0, total_elements = 0;
while(select!=4)
{
printf("nSelect a numbern1. pushn2. popn3. displayn4. exitn");
scanf("%d",&select);
switch (select)
{
case 1:
printf("Enter element to push: ");
int ele;
scanf("%d",&ele);
push(arr,&size,ele,&total_elements);
break;
case 3:
display(arr, &total_elements);
break;
case 4: break;
default:
break;
}
}
}
输入3个元素(11,22,33)后。push函数的打印输出
11 22 33
显示功能的打印输出。
11 22 -1943936495
我敢肯定,有一个错误的推函数,而使用指针。这是为什么呢?
由于arr = temp;
的存在,push
功能正常。注意,arr
实际上是push
函数内部的一个局部变量。当push
函数返回时,main
不知道push
中arr
变量被更改过。
当你将arr
传递给display
时,将发送main的副本。如果您需要在另一个函数(本例中为push
)中更新arr
,则需要传递arr
-push(&arr,&size,ele,&total_elements);
的地址。同样,push
函数现在应该接受int **arr
而不是int *arr
。另外,要确保在push
中正确地解引用arr
的次数。
在push
内部,您可以通过执行*arr = temp;
来更新arr
。在此之后,arr
将指向push
中malloc
的新数组,您可以将arr
传递给display
函数。
在你的代码中:
arr
为数组指针。size
是当前已填充/已使用元素的数量。total_elements
为分配的元素个数。
您过度分配arr
(使用total_elements
),这是好的。
但是,您混淆使用size
和total_elements
。在display
中,您应该使用size
。
注意,在main
中,您是而不是将arr
[初始化为NULL
]。对于您的代码,这是可以的,因为push
的实现方式。但是,通常最好将其设置为NULL
——见下文。
在push
中,不是为调用者更新arr
。
而且,push
比它需要的更复杂(即)太多的特殊情况。
如果main
初始化了arr
,那么push
可以直接使用realloc
(因为realloc
处理空指针就像在做malloc
[内部]一样)。
我们可以为包含单独标量值的数组创建一个控件struct
,而不是将3个东西传递给push
。这极大地简化了代码。我们只是把[单个]struct
指针传递给所有的函数。
下面是一些重构的代码。出于测试目的,我添加了一个case 5
:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *arr; // pointer to array data
int size; // number of filled/inuse elements
int total_elements; // number of allocated elements
} dynarr_t;
void
display(dynarr_t *dyn)
{
if (dyn->size == 0) {
printf("No elements present in arrayn");
return;
}
int totlen = 0;
for (int i = 0; i < dyn->size; i++) {
if (totlen >= 68) {
printf("n");
totlen = 0;
}
int curlen = printf(" %d",dyn->arr[i]);
totlen += curlen;
}
if (totlen > 0)
printf("n");
}
void
push(dynarr_t *dyn,int ele)
{
// grow the array
if (dyn->size >= dyn->total_elements) {
// the amount here is arbitrary
dyn->total_elements += 10;
dyn->arr = realloc(dyn->arr,sizeof(*dyn->arr) * dyn->total_elements);
// out of memory
if (dyn->arr == NULL) {
perror("push");
exit(1);
}
}
// append new element
dyn->arr[dyn->size++] = ele;
}
// RETURNS: 1=valid, 0=empty
int
pop(dynarr_t *dyn,int *ele)
{
// no elements in array
if (dyn->size <= 0)
return 0;
// pop the last element
*ele = dyn->arr[--dyn->size];
return 1;
}
int
main(void)
{
int select = 0;
int ele;
// allocate a pointer to the array control struct
dynarr_t *dyn = calloc(1,sizeof(*dyn));
while (select != 4) {
printf("nSelect a numbern1. pushn2. popn3. displayn4. exitn");
scanf("%d", &select);
switch (select) {
case 1:
printf("Enter element to push: ");
scanf("%d", &ele);
push(dyn, ele);
break;
case 2:
if (pop(dyn,&ele))
printf("main: pop %dn",ele);
else
printf("main: pop emptyn");
break;
case 3:
display(dyn);
break;
case 4:
break;
case 5: // internal test
for (int ele = 1; ele <= 100; ++ele)
push(dyn,ele);
display(dyn);
break;
default:
break;
}
}
// free up the memory
free(dyn->arr);
free(dyn);
return 0;
}
以下是[5 4
]的测试输出:
Select a number
1. push
2. pop
3. display
4. exit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
96 97 98 99 100
Select a number
1. push
2. pop
3. display
4. exit