I'm learning C language and I have a question about dynamic memory allocation.
Consider that I have a program that the user must enter numbers or typing the letter "E" to exit the program.
The numbers that the user enter must be stored in a one-dimensional array. This array begins with a single position.
How can I do to increase my array of integers to each number that the user enters to store this number in this new position? I think I must use pointers correct? And then, how do I print the values stored in the array?All the examples I find are complex to understand for a beginner. I read about the malloc and realloc functions but I don't know exactly which one to use.
Can anyone help me? Thanks!
void main() {
int numbers[];
do {
allocate memory;
add the number to new position;
} while(user enter a number)
for (first element to last element)
print value;
}
If you need to expand an array at runtime, you must allocate memory dynamically (on the heap). To do so, you can use malloc or more suitable for your situation, realloc.
A good example on this page here, which I think describes what you want.: http://www.cplusplus.com/reference/cstdlib/realloc/
Copy pasted from the link above:
/* realloc example: rememb-o-matic */
#include <stdio.h> /* printf, scanf, puts */
#include <stdlib.h> /* realloc, free, exit, NULL */
int main ()
{
int input,n;
int count = 0;
int* numbers = NULL;
int* more_numbers = NULL;
do {
printf ("Enter an integer value (0 to end): ");
scanf ("%d", &input);
count++;
more_numbers = (int*) realloc (numbers, count * sizeof(int));
if (more_numbers!=NULL) {
numbers=more_numbers;
numbers[count-1]=input;
}
else {
free (numbers);
puts ("Error (re)allocating memory");
exit (1);
}
} while (input!=0);
printf ("Numbers entered: ");
for (n=0;n<count;n++) printf ("%d ",numbers[n]);
free (numbers);
return 0;
}
Note that the size of the array is remembered using countvariable
Related
I am trying to create a function that will ask the user to input a number to determine the size of an array and then input numbers into the array. I then need to print the array and interchange the smallest and largest numbers in it. This is in C language
#include <stdio.h>
void read_array();
void display_array();
void read_array(int arr[])
{
int Size;
printf("Enter the desired size of the array: ");
scanf("%d", &Size);
for(int i = 0; i < Size; i++)
{
printf("\nEnter a number for position %d:", i);
scanf("%d", &arr[i]);
getchar();
}
}
int main()
{
int size;
int arr[size];
read_array(arr[size]);
return 0;
}
Regarding the creation of the array, you have 3 options (ordered by my own preference).
In this example get_array_size() is a function that returns the number of elements entered by the user and process_array() does something with the created array (like filling it with more user input).
1.) Use a fixed length array
int array[10];
unsigned int size = get_array_size();
if (size > 10) {
printf("Size is too large.\n");
exit(1);
}
process_array(array, size);
This has the benefit that it's always clear how much memory your program will consume: 10 elements of the size of int.
Obviously, if the user enters a number less than 10 (in this example) the remainder of the array would be "wasted".
2.) Allocate the array on the heap
unsigned int size = get_array_size();
// It's still advised to "cap" the max. size of your array
if (size > 32) {
printf("Won't allocate: size is too large.\n");
exit(1);
}
int *array;
array = calloc(size, sizeof(int));
if (!array) {
printf("Could not allocate memory!\n")
exit(1);
}
process_array(array, size);
free(array);
Note the use of the free() function.
Here only what is needed/requested will be allocated (if the user enters 5 only 5 elements will be allocated).
Downside is you have to free() the allocated memory once you're done with it.
And even here, it's very much advised to set a maximum number of elements anyway (you don't want your program to, say, allocate 4GB of ram for a simple task that doesn't require it)
3.) Allocate the array on the stack
unsigned int size = get_array_size();
// It's still advised to "cap" the max. size of your array
if (size > 32) {
printf("Won't allocate: size is too large.\n");
exit(1);
}
int array[size];
process_array(array, size);
Same as option 2 except that you don't free() the memory after use. However, other limitations come into play (you can't return an array allocated like this from a function) and you definitely don't want to overflow your stack.
So you see, no matter which option you choose: it's practically always needed to enforce a maximum anyway, so I'd go with the first option whenever possible (consider stack size).
In all cases, the process_array function can be implemented in the same way (the function doesn't care where the memory is coming from):
void process_array(int *array, unsigned int size) {
for (unsigned int i = 0; i < size; ++i) {
// do something with array[i]
}
}
The bottom line is: if you want to program in C, you really have to understand these concepts. If this is too much for you, choose another language that does the memory handling for you.
I just wanted to ask that is there any way to dynamically allocate memory to an existing array of elements at runtime in C? For example.. if i declared int arr[25]; then I would be able to take maximum of 25 integers in my array.. But what if the user wants to enter some more integers.. but we dont know in advance how many? Also I dont want to waste the memory by assigning something like int arr[500]; just to be sure that the user doesnt exceed the upper bound of my array :( I'm really confused and sad as I'm unable to find a solution for this.. Does C even support such kind of thing? If not then in which programming language would it be easier to tackle a problem like this? P.S-> I'm new to programming so I'm sorry if this is a noob question. :/
you need to do dynamic memory allocation using malloc()/realloc() and release it using free() once you are done.
int* a = malloc(25*sizeof(int));
//use a like array...a[0]...to a[24]
// realloacte if you need to grow it
a = realloc(a,50);
free(a);
The above logic should be used in C. If you are writing into C++, you should use STL std::vector<T>
if it is an array you might actually want to check out the calloc() function:
void* calloc (size_t num, size_t size);
It can be used like so:
/* calloc example */
#include <stdio.h> /* printf, scanf, NULL */
#include <stdlib.h> /* calloc, exit, free */
int main ()
{
int i,n;
int * pData;
printf ("Amount of numbers to be entered: ");
scanf ("%d",&i);
pData = (int*) calloc (i,sizeof(int));
if (pData==NULL) exit (1);
for (n=0;n<i;n++)
{
printf ("Enter number #%d: ",n+1);
scanf ("%d",&pData[n]);
}
printf ("You have entered: ");
for (n=0;n<i;n++) printf ("%d ",pData[n]);
free (pData);
return 0;
}
If you need to resize the array later look at the realloc function. (and yes it does keep the original data if succesfull)
There is a class in c++ that you may find useful, which is called a vector. You can add to the front of a vector: myVector.push_front(myElement) and to the end of a vector: myVector.push_back(myElement). If this type of functionality is very important to you, I would recommend using a c++ vector.
Alternately, you can use the malloc() function in c to request a specific amount of memory at runtime: char *five_chars = malloc(sizeof(char) * 5). Just be sure to call free(five_chars) when you're done with the memory.
I want to store an array of strings , count their length and re-arrange them with length-increasing-order (smallest->larger) using the algorithm mentioned below //
Swap holds a relatively big string to replace the order (when another min is found)
I could use realloc() but I am not considering defend programming yet
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i,j,N;
printf("\n Input amount of alphanumericals: ");
scanf("%d",&N);
{
int min;
char *swap=(char*)malloc(sizeof(char)*150);
char *A[N],**temp;
temp=A;
for(i=0;i<N;i++){
printf("\nInput %d element:",i+1);
fgets(temp+i,150,STDIN);
}
printf("\n\nData [");
for(i=0;i<N;i++)
printf(" %s",A[i]);
printf(" ]\n\n");
//Ins sort
for(i=0;i<N;i++){
min=i;//Assume current is min
for(j=i+1;j<N;j++){
//Compare assuming min with current
if(strcmp(A[j],A[min])<0){
min=j;
}
//If next is min replace in current position
if(min!=i){
swap=A[i];
A[i]=A[min];
A[min]=swap;
}
}
free(swap);
printf("\nAfter insertion point algorithm\n");
printf("\n\nInsertion Sorted Data [");
for(i=0;i<N;i++)
printf(" %s",A[i]);
printf(" ]");
}
return 0;
}
You are tying to free memory that has not been allocated using malloc:
char *A[N],**temp;
temp = A; // A is an automatic (AKA "stack") variable; now temp points to it as well
free(temp); // Undefined behavior
Inside the loop you are reading with gets into strings that have not been allocated:
gets(temp+i); // That's the same as gets(A[i]); Your A[i]s are unallocated.
As a side note, you should not use gets, because it is a prime source of buffer overruns. Use fgets instead, and pass stdin as the FILE* parameter. scanf with %20s is another alternative to limit the size.
In addition, since i goes from 1 to N, inclusive, this expression references one element past the A array on the last iteration:
gets(temp+i); // Undefined behavior when i==N
EDIT : Why is the code below crashes?
for(i=0;i<N;i++){
printf("\nInput %d element:",i+1);
fgets(temp+i,150,STDIN);
}
The code below crashes because you did not allocate memory for the individual strings:
for(i=0;i<N;i++){
printf("\nInput %d element:",i+1);
temp+i = malloc(151); // No need to multiply by sizeof(char) or cast to char*
fgets(temp+i,150,STDIN);
}
Note that you need to allocate one extra char for the null terminator.
You are not using gets correctly: take a look at its manual page [1]. Moreover, using gets is not recommended: better use fgets.
Also, gets is not allocating the string for you, so when you pass it a char * pointer, the pointer has to point to a valid memory location. Instead, your A[n] is an array of dangling pointers.
Then, why free(temp)? You must call free for each pointer allocated with malloc: not the case for temp.
Finally, please format your code: use indent.
[1] http://linux.die.net/man/3/gets
I need to have an array of structs in a game I'm making - but I don't want to limit the array to a fixed size. I'm told there is a way to use realloc to make the array bigger when it needs to, but can't find any working examples of this.
Could someone please show me how to do this?
Start off by creating the array:
structName ** sarray = (structName **) malloc(0 * sizeof(structName *));
Always keep track of the size separately:
size_t sarray_len = 0;
To increase or truncate:
sarray = (structName **) realloc(sarray, (sarray_len + offset) * sizeof(structName *));
Then set the size:
sarray_len += offset;
Happy to help and hope that helps.
The realloc function can be used to grow or shrink an array. When the array grows, existing entries retain their value and new entries are uninitialized. This may either grow in-place, or if that was not possible, it may allocate a new block elsewhere in memory (and behind the scenes, copy all the values over to the new block and free the old block).
The most basic form is:
// array initially empty
T *ptr = NULL;
// change the size of the array
ptr = realloc( ptr, new_element_count * sizeof *ptr );
if ( ptr == NULL )
{
exit(EXIT_FAILURE);
}
The multiplication is because realloc expects a number of bytes, but you always want your array to have the right number of elements. Note that this pattern for realloc means you do not have to repeat T anywhere in your code other than the original declaration of ptr.
If you want your program to be able to recover from an allocation failure instead of doing exit then you need to retain the old pointer instead of overwriting it with NULL:
T *new = realloc( ptr, new_element_count * sizeof *ptr );
if ( new == NULL )
{
// do some error handling; it is still safe to keep using
// ptr with the old element count
}
else
{
ptr = new;
}
Note that shrinking an array via realloc may not actually return memory to the operating system; the memory may continue to be owned by your process and available for future calls to malloc or realloc.
From http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/
/* realloc example: rememb-o-matic */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int input,n;
int count=0;
int * numbers = NULL;
do {
printf ("Enter an integer value (0 to end): ");
scanf ("%d", &input);
count++;
numbers = (int*) realloc (numbers, count * sizeof(int));
if (numbers==NULL)
{ puts ("Error (re)allocating memory"); exit (1); }
numbers[count-1]=input;
} while (input!=0);
printf ("Numbers entered: ");
for (n=0;n<count;n++) printf ("%d ",numbers[n]);
free (numbers);
return 0;
}
I'm just starting on the road the learning C, and ran into some difficulty:
The code listed below is giving me the following error:
Attaching to program: `/workfolder/cocoa/c_stuff/bookshelf/build/Debug/bookshelf', process 1674.
Cannot access memory at address 0xa0df194
Cannot access memory at address 0xa0df194
// code start
#define MAX_NAME_LENGTH 200
#define MAX_AUTHOR_LENGTH 200
#define MAX_DESCRIPTION_LENGTH 1000
#define MAX_PUBLISHER 200
#define MAX_ISBN 50
//structures<
typedef struct {
char title[MAX_NAME_LENGTH];
char author[MAX_AUTHOR_LENGTH];
char ISBN[MAX_ISBN];
char description[MAX_DESCRIPTION_LENGTH];
char publisher[MAX_PUBLISHER];
} Book;
void getUserInput(Book *s[])
{
printf("what is the book's title ?\n");
fgets(s[book_count]->title, MAX_NAME_LENGTH, stdin);
printf("what is the author's name?\n");
fgets(s[book_count]->author, MAX_AUTHOR_LENGTH, stdin);
printf("what is the ISBN?\n");
fgets(s[book_count]->ISBN, MAX_ISBN, stdin);
printf("write a short description\n");
fgets(s[book_count]->description, MAX_DESCRIPTION_LENGTH, stdin);
printf("what is the book's publisher\n");
fgets(s[book_count]->publisher, MAX_PUBLISHER, stdin);
printf("want to add another book ? Y\\N\n");
book_count++;
if(tolower(fgetc(stdin)) == 'y')
{
return getUserInput(s);
}
else
{
return;
}
}
int main (int argc, const char * argv[]) {
// insert code here...
Book *book_shelf[100];
if((book_shelf[0] = (Book *)malloc(sizeof(Book))) == NULL)
{
exit(1);
}
getUserInput(book_shelf);
return 0;
}
The code compiles properly, and the function runs fine the first time (all the questions get asked and the struct receives the data); but when the user types 'y' to add another book, the mem error occurs.
Any ideas where the error is happening?
Thanks in advance!
You've only ever allocated memory for the first book in main - after that it tries to write to the next slot in the array, which doesn't point to an allocated block of memory, giving you a seg-fault. You're going to have to allocate memory for each book you want to read in.
In addition, since C doesn't know how long an array is, you have to pass that information along into function calls. (And I don't see where you're defining book_count.)
You might try something along these lines:
void getUserInput(Book *s[], int *book_count, int max_book_count)
{
if (book_count == max_book_count) return; // If we've filled all the slots, we can't add anymore without causing trouble.
s[book_count] = malloc(sizeof(Book));
..
if(tolower(fgetc(stdin)) == 'y')
{
(*book_count)++;
getUserInput(s, book_count, max_book_count);
}
return;
}
int main (int argc, const char * argv[]) {
// insert code here...
Book *book_shelf[100];
int book_count = 0;
getUserInput(book_shelf, &book_count, 100);
// Make sure to free all the malloc'd data
}
Even better in this situation, would just be using a loop and skipping the whole recursion step.
int main (int argc, const char * argv[]) {
// insert code here...
Book *book_shelf[100];
char response = 'y';
int book_count = 0;
while (book_count < 100 && response == 'y')
{
book_shelf = malloc(sizeof(Book));
response = getUserInput(book_shelf[book_count++]);
}
// make sure to free all the allocated data!
}
char getUserInput(Book *book)
{
// write input straight to book
printf("what is the book's title ?\n");
fgets(book->title, MAX_NAME_LENGTH, stdin);
...
return tolower(fgetc(stdin));
}
Unless I'm reading something wrong, you haven't defined book_count before using it as an array subscript.
Within main, you allocated on the stack an array of 100 pointers to the Book Structure. I believe it was your intent to allocate 100 structures and then pass the address to that block of structures to getUserInput
Change main to:
Book book_shelf[100];
...
getUserInput(book_shelf);
...
EDIT: OOPS Missed the single Book malloc mentioned in the earlier post. That ones Correct for the first book. If you edit as above and eliminate the
if (book_shelf[0]...) check, you'll accomplish your intended results
You allocate just space for the firstbook, not for the others (malloc in main)
I guess there is some code missing, no declaration and initialization of book_count
You should use loops instead of recursion
Use not recursion but loops for this kind of repetition
Recursion is probably overkill for this problem where a simple do { ... } while(user keeps answering yes) would do. However the problem you having is in main with your Book *book_shelf[100]. There are several ways you could solve this problem.
First change it to an array of Book's like samills suggests:
Book book_shelf[100];
and then change your getUserInput to something like this:
getUserInput(Book *book_shelf, int offset, int length) {
if(offset < 0 || offset >= length) {
return;
}
//...
return getUserInput(book_shelf, offset + 1, length)
}
Or you could use your existing code and change you getUserInput function to look something like this and remove the malloc from main:
getUserInput(Book *book_shelf) {
book_shelf[book_count] = (Book*)malloc(sizeof(Book));
// ...
}
props for correct use of the sizeof operator (I see that thing misused so often it makes my eyes bleed).
As in Josh's answer, by adding the following lines to your code should make it work:
book_count++;
if(tolower(fgetc(stdin)) == 'y')
{
if((book_shelf[book_count] = (Book *)malloc(sizeof(Book))) == NULL)
{
printf("Cannot allocate memory for Book");
exit(1);
}
return getUserInput(s);
}
else
{
return;
}
However, I encourage you not to use the recursive function for getting input. Recursive can lead to difficulties in debugging. You may consider using normal loop instead.
Note: I'm assuming the book_count is global variable which has been initialized to 0
thanks a lot for the replies!
I realized that I hadn't malloc-ed enough memory to handle more then one element of the struct array (Exactly what Josh is saying). So essentially:
Book *book_shelf;
if(book_shelf = (Book*)malloc(sizeof(Book)) == NULL)//exit code
so the second time around I would hit a memory issue.
thanks again!
Looks like your still doing it wrong:
Book *book_shelf;
if(book_shelf = (Book*)malloc(sizeof(Book)) == NULL)//exit code
book_shelf is only the size of a pointer. When you do the malloc you only allocate one Book at a time. This is wrong. You need to allocate contiguous memory for an array of Book objects all in one instanciation of an array.
Like
Book book_shelf[100];
not
Book *book_shelf[100];
or using malloc, use your pointer to point to an array instanciated using
100*malloc(sizeof(Book)).
You may get lucky that no other heap memory is allocated in between your malloc(sizeof(Book)) calls and that the memory management system is alocating contiguous memory by default. Also, book_shelf will only point to the last malloced Book structure, not the first one as you indicated you want in your original question.
Josh is also not allocating enough memory at one time. Use a linked list if you want to keep extending elements to the end of your book_shelf one-by-one.
factorial with pointer and recursion
#include<iostream.h>
#include<conio.h>
int show(int *p)
{
int f;
int x=*p;
if(*p==1) //boundry checking for recursion
return 1;
else
f=x*show(&(--*p)); //this code is similar to f=x*show(n-1); with non-pointers
return f;
}
void main()
{
int a=6;
int b=show(&a);
cout<<b;
getch();
}