snakec
snakec

Reputation: 135

Using dynamic memory in C

I'm a novice user of C language. I have a problem in allocating a dynamic array.

I used to allocate memory outside the loop such as a=(int*)malloc(5* sizeof(int)); and every thing worked fine. Now I want to allocate memory to each element one by one in a loop using malloc(), but the code is not working.

I've tried different options like scanf("%d",a) &a++,scanf("%d",&a[i]); etc but could not succeed. If anyone can tell me what I was doing wrong and explain to me the concept thoroughly, I'll be thankful.

The code which I'm having problems with is the following:

#include <stdio.h>
#include<stdlib.h>

int main()
{
  int *a;
  int i;
  system("clear");

  for(i=0;i<5; i++)
  {
    a=(int *)malloc(sizeof(int));
    printf("%u",&a);
    printf("please enter the element in array");
    scanf("%d",a[i]);
  }
  for(i=0;i<5; i++)
  {
    printf("\nthe %d entry in the array %d",i,a[i]);
  } 
  return 0;
}

Upvotes: 1

Views: 296

Answers (8)

user191776
user191776

Reputation:

I believe I have found the solution to your predicament. Simply follow these steps:

(1) Shift the statement:

a=(int *)malloc(sizeof(int));

out of the for loop (put it just before the for), & change it to:

a=(int *)malloc(5 * sizeof(int));

(2) Change your scanf statement to:

scanf("%d",&a[i]);

That should do the trick.

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 753595

As everyone has pointed out, you really don't want to allocate each element of the array separately. However, if, despite the advice, you decide you do, then you need both an array of pointers and the individual pointers:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
enum { ARRSIZE = 5 };

static void err_exit(const char *msg)
{
    fprintf(stderr, "%s\n", msg);
    exit(1);
}

int main()
{
  int **a;
  int i;
  a = (int **)malloc(sizeof(*a)*ARRSIZE);
  if (a == 0)
      err_exit("out of memory");

  for (i = 0; i < ARRSIZE; i++)
  {
    a[i] = (int *)malloc(sizeof(int));
    if (a[i] == 0)
        err_exit("out of memory");
    printf("%" PRIuPTR "\n", (uintptr_t)a[i]);  // Print allocated address
    printf("please enter the element in array: ");
    if (scanf("%d", a[i]) != 1)
        err_exit("failed to read a valid integer");
  }
  for (i = 0; i < ARRSIZE; i++)
  {
    printf("the %d entry in the array %d\n", i, *a[i]);
  }
  return 0;
}

Additional points:

  • Check that malloc() worked.
  • Using scanf() can lead to a world of pain. You should check its return status too. If you type a letter instead of a digit, your code will fail rather horribly. Generally, you are better off using fgets() and sscanf().
  • Print newlines at the end of lines of output - especially in the print loop.
  • Use (your own) standardized error reporting functions similar to err_exit(); that is just a trivial version of what could be a much more complex system of functions, but having such functions available means you are less likely to skimp on error reporting.
  • Use more white space. Use space around most operators. I recommend using a bigger indent than 2 (either 4 or 8).
  • Avoid magic numbers (like 5) if they appear more than once in the code. 0 and 1 are not magic numbers.
  • Use the uintptr_t to print addresses as integers, and the <inttypes.h> header, and the names defined in there such as PRIuPTR. (I usually print addresses in hex, but decimal isn't automatically wrong.) The <inttypes.h> header is from C99; that might cause you problems if your C compiler is retrograde enough not to provide C99 support.
  • Note that this is not the recommended solution for your problem with int type; on a 64-bit machine, it uses vastly more memory than the original solution.
  • However, if you were dealing with an array of separately allocated large structures and you were not sure in advance exactly how many you'd need, then this scheme would be more sensible. (You'd probably not be tied to a fixed array size, though.)
  • There are those who cavil at the cast on the return type from malloc(). I prefer it, in part because I learned C on a machine where the cast was crucial, and in part because the cast is mandatory in C++, and I like my code to work in the C subset of C++ even when I'm writing in C. (The compiler in question was before there was a standard C; it was word-addressed machine; malloc() returned char *, but the bit pattern for a char * was different from the bit pattern for an anything * (e.g. int *) to the same address.)

Upvotes: 1

user191776
user191776

Reputation:

a[i] is equivalent to *(a+i)

scanf needs the address of a which can be supplied here by using &(a[i]) or simply (a+i). Instead, you are passing it a[i], which refers to data stored at the location (a+i).

Upvotes: 1

sorpigal
sorpigal

Reputation: 26086

unwind's answer is the explanation, but here's some code to demonstrate

#include <stdio.h>
#include <stdlib.h>

int main(){
    int *a;
    int size = 5;
    int i = 0;
    a = malloc(sizeof(int)*size);

    for(i=0;i<size;i++){
            printf("%u: ",&a);
            printf(" please enter the element in the array> ");
            scanf("%d", &a[i]);
    }

    for(i=0;i<size;i++){
            printf("index %d in the array is %d\n",i,a[i]);
    }

    free(a);

    return 0;
}

Upvotes: 0

Alexander Rafferty
Alexander Rafferty

Reputation: 6233

The whole thing is, to be honest, a disaster. If you are learning and are completely confused, try reading up on C pointers.

Look, perhaps try something like this:

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *a;
int i;
system("clear");

a=(int *)malloc(sizeof(int)*5);

for(i=0;i<5; i++)
{
  printf("please enter the element in array");
  scanf("%d",a+i);
}

for(i=0;i<5; i++)
{
  printf("\nthe %d entry in the array %d",i,a[i]);
}

return ;
}

Or the way I would do it:

#include <vector.h>
#include <stdio.h>

int main()
{
  vector<int> a;
  int i;
  system("clear");

  for(i=0;i<5;i++)
  {
    printf("please enter the element in array");
    int n;
    scanf("%d",&n);
    a.push_back(n);
  }

  for(i=0;i<5; i++)
  {
    printf("\nthe %d entry in the array %d",i,a[i]);
  }

  return ;
}

You see, you cannot simply allocate new memory and expect to be "added" to previously allocated memory. The only way to add to or resize a block of memory is to recreate it, and carry over the data.

Upvotes: -1

unwind
unwind

Reputation: 399763

An array is a single "object" (a single thing) that has space for many items, all of the same type.

Your expectation to be able to somehow allocate one item at a time is incorrect, that's simply not how arrays work.

You should do like you first said, a single malloc() allocating room for 5 items, and then just store each one to its proper position in the array inside the loop.

I would recommend using scanf("%d", &a[i]) to read and store into the array. There are other ways of writing the second argument, but this (in my opinion) is the clearest and best for a beginner. It reads as "the address of the i:th item in the array a".

Upvotes: 5

kafbuddy
kafbuddy

Reputation: 304

The problem is that you create a new array with size = 1 everytime in the for loop.

So everytime "a" has place for one integer.

Upvotes: 0

harper
harper

Reputation: 13690

In each iteration your code overwrites the old value of a. So you lose the address of the previously mallocated memory.

Each malloc allocates only sapce for one int. It's illegal to dereference the pointer with an index > 0. That's why your code gives undefined behaviour.

Upvotes: 1

Related Questions