problems with data entry and malloc in C
I'm new to C and I'm having a small problem with my code:
int i, n;
int *arr;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
exit(1);
else {
arr = (int*) malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
} //end if
} //end while
What I'm trying to do is to make an array of n size and I want to stop reading when I get a '0' for example if I enter:
3
2
2
5
2
6
7
0
I want an array of size 3 with values 2, 2, 5, an array of 2 with values 6 and 7 and exit because of the 0 * Sorry, I left out an important part I think... In my code a call a calc() where I send arr, right after scanf("%d",&arr[i]) and then i'll return the value and then if the next values e.g. 2 开发者_Go百科isn't 0 I'll read, create a new array, send arr, print result on console and again if the next value is 0 then it will exit. * Could you guys tell me where I'm wrong?
You are almost there!
You are creating the new arrays in arr
, but this is a single pointer so can only refer to one block of memory. When you call malloc the new memory is stored in arr
but the old memory is lost. You are 'leaking memory' because the machine has the old memory reserved but you don't have a variable storing it's address so you have no way to find it again.
If you only need to store the last list you should free the old memory (in arr) before malloc'ing the new space. If you need to store all the arrays you will need an array of pointers in arr.
edit:
You need to call free to 'free' the previously allocated memory before you allocate the new memory. At the first set of data you don't have any existing 'malloc' but it's always safe to free a NULL pointer, so simply set the pointer to NULL at the start.
Hint: It's always a good idea to set all the variables to some safe initial value when you define them.
int *arr=NULL; // Mark this as pointing to no memory
....
free(arr); // first time it does nothing, afterwards it deletes the previous reserved memory
arr = (int*) malloc(sizeof(int) * n); // as before this reserves some memory
The problems which are visible in your code are:
1. Checking uninitialized integer n
in while
. To fix this either initialize n
to non zero or use a do{ ... } while()
instead of while()
.
2. You need to validate the value of n
which is read through scanf
. malloc
takes size_t
type as the parameter which is unsigned int
. But n
being an integer can accept negative values, thus if a negative value is entered it will be passed as unsigned int
to malloc
, this may lead to undesired results (Also for
loop will be executed incorrect number of times). You may also consider changing the type of n
from integer
to unsigned int
type or change the exit condition to if( n < 1 )
.
3. There is memory leak in your program. Memory allocated through malloc
is not freed through free
.
4. Do not assume that malloc
will always succeed. Please check for the success of malloc
through a NULL
check i.e.
if (NULL == arr)
{
//error handling
}
5. exit
with non zero value generally indicates abnormal termination. You can use break
or return
. break
might be a better idea as it generally gets difficult to test a function as the exit points in the function increase (though this may not be true in your case, but it is FYI)
6. Optionally, you can check the return value of scanf
to make sure that a valid input was entered.
Help this helps!
You're not initializing n
so you may or may not enter your while
loop. Starting n
at -1 would be a reasonable thing to do:
int i, n = -1;
And you should cast the return value of malloc
, that can hide problems.
You're also leaking memory because you're not calling free
on that you get back from malloc
and you're losing track of what you read in every time you assign a new value to arr
. Brian Roach and Martin Becket have mentioned these things though.
Presumably you want to be able to access these arrays later.
As it is, you're losing your pointer to the previous array when you malloc
the next one (and of course, causing a memory leak if it were a larger application).
You need to allocate a chuck of int *
(a set of int
pointers) then store each int
pointer there.
The trick is ... if you don't know how many arrays you're going to need, you need your code to be dynamic (for example; allocate some amount of space, then allocate more if you run out).
Another option is that you could limit the number of series the user can input and tell them they're done when they reach it.
Here's some help if you wanted to go the latter route:
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5); /* max of 5 arrays */
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
HOWEVER ... now you don't know how long each array is. Which is a problem. You'd need to keep track of that, or use a dynamic structure such as a linked list. In the example below, we add the length as the first element of each array:
int main()
{
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5);
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * (n + 1)); /* one more than we need */
arr[0] = n; /* store the array length in the first element */
for(i = 1; i <= n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
int j;
for (i = 0; i < arrayCount; i++)
{
int length = myArrayOfArrays[i][0]; /* retrieve the length */
for (j = 1; j <= length; j++)
printf("%d ", myArrayOfArrays[i][j]);
printf("\n");
}
}
Dynamic allocation using arrays / raw memory means you need to keep track of stuff. The better approach really is using a linked list for your data. In this case, you could have a linked list of nodes, each of which contained a link list of integers.
精彩评论