简体   繁体   中英

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 eg 2 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 ie

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!

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM