Dynamic Memory Allocation and multi-level arrays in C - c

Q6: Dynamic Memory allocation: Consider the following declaration for the multi-level array,
names:
char name_1[]= “John”;
char name_2[]= “Paul”;
char name_3[] = “Stephen”;
char *names[3]={name_1, name_2, name_3};
Create an equivalent multi-level array: dynamic_names that has all its elements and the data
pointed to by its elements on the heap.
What exactly does this even mean? seems a little broad and with no direction to put me in... Would be very awesome to help!
Thanks!

Create an equivalent multi-level array: dynamic_names that has all its elements and the data pointed to by its elements on the heap.
The ...multi-level array with all its elements in heap... : char **dynamic_names; (Only a pointer because the space will be allocated dynamically using malloc).
Now the 3 elements in the array dynamic_names i.e. ...the data pointed to by its elements... also need to be in heap, therefore, each of the char *name_1; , char *name_2; ; char *name_3; will also be allocated memory dynamically similarly using malloc.
P.S. : I have explained the problem in words. Try to figure out how to write the code for it. :)
EDIT: (After OP's Comment)
More explanation:
The multi-level array dynamic_names will point to 3 char* pointers.
Each of the three pointers name_1 and similar will point to 1 char array of different sizes.
To allocate a space of 5 chars and assign it to a char * pointer, you write:
char *ptr = malloc(5 * sizeof(char));
[Sincere Advice: Don't cast return value of malloc]
EDIT 2:
char **dynamic_names = malloc(3*sizeof(char*)); This will allocate space for 3 char* pointers, and assign the base address of the allocated space to dynamic_names.
char *name_1 = malloc(10*sizeof(char)); This will allocate space for a string/array of size 10 (including '\0'), and assign the base address of the space to name_1.
strncpy(name_1, "John", 5); This will initialize the space allocated for the first string (pointed to by name_1) with "John".
dynamic_names[0] = name_1; this will assign "the pointer to first string" as the first element of the dynamic_names array.
Now you have to allocate space for other two strings and provide their base addresses to name_2 and name_3 and then assign these pointers as second and third elements resp. to dynamic_array.

Related

How do array pointers work in C and how to change pointers

I'm very new to C and I have trouble understanding array pointers. I'm trying to make a array bigger,I copy all of its element to new bigger array but I can't make original variable to point the new array. I'm use to C# where you can do
double[] array1 = new double[5];
double[] array2 = new double[10];
array1 = array2;
I did something similar using int array
int array1 [5];
int array2 [10];
*array1 = &array2;
and it compile but crash the program. Same lines but double or char[] (I was told to use char[] instead of sting in C) do not even compile
[Error] incompatible types when assigning to type 'double' from type 'double (*)[(sizetype)(newsize)]'
The results I found on the topic told me to use double* array1 for variable type but this change the interactions with that variable.
If someone can explain the concept to me or at least tell me what to search for that will be huge help.
I do know the basics of pointers!
There are a few things you need to know about arrays (and pointers):
The first is that arrays and pointers are two different things;
The second is that an array can decay to a pointer to its first element. So if you use array1 (from your example) when a pointer is expected, that's the same as doing &array1[0]. The type of such a pointer is a pointer to a single element type (so for array1 the type will be int *);
The third thing is that for any array of pointer a and index i, the expression a[i] is exactly equal to *(a + i). That means *array1 (again from your example) is the same as array1[0] (*array1 is equal to *(array1 + 0) which is equal to array1[0]);
An array will have a fixed size. Once defined the size of an array can't change;
Lastly when you get a pointer to an array (as in &array2) then you get a pointer to the actual array, not to one of its elements. The type of e.g. &array2 is int (*)[10].
Now we can puzzle together the statement
*array1 = &array2;
If we do the array-indexing replacement for *array1 then we get
array[0] = &array2;
And here we can see a big problem: The type of a single element of array1 is a plain int. So what the assignment is trying to do is to assign a pointer to an array (of type int (*)[10]) to a single int.
If you want to copy all the elements from one array to another, then use the memcpy function. You're not allowed to assign between arrays.
But beware of the different sizes for array1 and array2. If you go out of bounds of an array (or other allocated memory) you will have undefined behavior.
In C there is no way to make an array variable "reference" a different variable. If you need to use "references" they can be emulated using pointers:
int *pointer1 = array1; // array1 here will decay to &array[0]
int *pointer2 = array2; // Same here for array2
With the above definition pointer1 is (in a way) "referencing" array1. You can now use pointer1 and array1 almost interchangeably.
One major difference between using pointers and arrays is how their sizes are calculated: When you do sizeof on an array you get the size (in bytes) of the whole array. Assuming 32-bit int (the most common) then sizeof array1 will return 5 * 4 (or 20) as the size. If you get the size of a pointer, you get the size of the pointer itself, not what it might point to. So sizeof pointer1 will return either 4 or 8 (depending on if you're in a 32-bit or 64-bit system).
Going back to references, we can now change where pointer1 is pointing:
pointer1 = pointer2; // Assuming pointer2 is unchanged, equivalent to pointer1 = array2
Now pointer1 and pointer2 are pointing to the same array, array2.
In C# you can overload the = to copy the arrays. In C it is just simple assignment.
In C arrays decays to pointers for the sake of simplicity. In C *(array + N) == array[N] and *array == array[0]
int array1 [5]; it is not the array of pointers only integers so *array1 = &array2; assigns array[0] with address of the first element of the the array2 converted to signed integer which generally doesn't make too much sense and it does not copy array2 to array
To copy array you need to use memcpy or the loop to copy the element. You need to make sure that the destination array is large enough to accommodate the second array. C will not change the destination array size.
The assignments that your are doing is wrong. Basically a pointer points to a block of memory. from your code I can understand that array1 = array2; and *array1 = &array2; is wrong.
Syntax in C is something like this data-type* pointer-variable = (data-type*)malloc(no. of bytes you want);
See consider you want 10 block of memory of type int
int *p = (int *)malloc(10 * sizeof(int))
sizeof(int) return 4 bytes.
Now p points to 10 * 4 = 40 bytes of memory, I multiplied by 4 because int is usually of 4 bytes and double is of 8 bytes and so on.
Follow this link to understand C - Data Types
Now regarding changing pointers refer below example and read the comments
int *q = NULL // declare a pointer of same type as the block of memory it is going to point
q = p; //now q and p point same memory of 40 bytes, means value at q[0] is equal to p[0]
When you have an integer pointer and you increment it by p++ it will point to next memory location p[1], pointer will be exactly incremented by 4 bytes as int size is 4 bytes and for double it will be 8 bytes, for char it will be 1 byte and so on.
Now if you want to increase the size of dynamically allocated memory you can use realloc please follow this link to understand more.
Dynamic Memory Allocation in C
int *p = NULL;
// Dynamically allocate memory using malloc()
p = (int*)malloc(no. of bytes, sizeof(int));
// Dynamically re-allocate memory using realloc()
p = realloc(p, (no. of bytes) * sizeof(int));
// Avoid memory leaks
free(p);
Syntax in C++ is something like this data-type* pointer-variable = new data-type[size];
See consider you want 10 block of memory of type int
int *p = new int[10]
Just use new operator to allocate block of memory and use delete to free allocated memory to avoid memory leaks.follow this link
new and delete operators in C++ for dynamic memory
Or If you are looking for containers where you don't know how much memory should be allocated the use standard template library vector, it helps creating dynamic arrays.follow this link
Vector in C++ STL

How to create a function that allocates an array to hold pointers

I understand I want to use malloc, but How do I have it hold pointers?
If I am given a number for the size of the array and I want each one of those indexes to point to another array.
Some input on how to start it would be helpful. I know its not too many lines of code but the concept is abstract to me making it hard to know where to start in the code.
Well malloc allocates an area of memory the size of so many bytes. So if you want to hold pointers in that memory, you'll need to multiply the size of a single pointer by how many you want in that area.
Here's a little example for an array of strings (which are just pointers)...
const char ** array_of_strings;
array_of_strings = malloc(2 * sizeof (const char *));/* size for two pointers */
array_of_strings[0] = "first string";
array_of_strings[1] = "second string";

What is the difference between using strcpy and equating the addresses of strings?

I am not able to understand the difference between strcpy function and the method of equating the addresses of the strings using a pointer.The code given below would make my issue more clear. Any help would be appreciated.
//code to take input of strings in an array of pointers
#include <stdio.h>
#include <strings.h>
int main()
{
//suppose the array of pointers is of 10 elements
char *strings[10],string[50],*p;
int length;
//proper method to take inputs:
for(i=0;i<10;i++)
{
scanf(" %49[^\n]",string);
length = strlen(string);
p = (char *)malloc(length+1);
strcpy(p,string);//why use strcpy here instead of p = string
strings[i] = p; //why use this long way instead of writing directly strcpy(strings[i],string) by first defining malloc for strings[i]
}
return 0;
}
A short introduction into the magic of pointers:
char *strings[10],string[50],*p;
These are three variables with distinct types:
char *strings[10]; // an array of 10 pointers to char
char string[50]; // an array of 50 char
char *p; // a pointer to char
Then the followin is done (10 times):
scanf(" %49[^\n]",string);
Read C string from input and store it into string considering that a 0 terminator must fit in also.
length = strlen(string);
Count non-0 characters until 0 terminator is found and store in length.
p = (char *)malloc(length+1);
Allocate memory on heap with length + 1 (for 0 terminator) and store address of that memory in p. (malloc() might fail. A check if (p != NULL) wouldn't hurt.)
strcpy(p,string);//why use strcpy here instead of p = string
Copy C string in string to memory pointed in p. strcpy() copies until (inclusive) 0 terminator is found in source.
strings[i] = p;
Assign p (the pointer to memory) to strings[i]. (After assignment strings[i] points to the same memory than p. The assignment is a pointer assignment but not the assignment of the value to which is pointed.)
Why strcpy(p,string); instead of p = string:
The latter would assign address of string (the local variable, probably stored on stack) to p.
The address of allocated memory (with malloc()) would have been lost. (This introduces a memory leak - memory in heap which cannot be addressed by any pointer in code.)
p would now point to the local variable in string (for every iteration in for loop). Hence afterwards, all entries of strings[10] would point to string finally.
char *strings[10]---- --------->1.
strcpy(strings[i],string) ----->2.
strings[i] = string ----------->3.
p = (char *)malloc(length+1); -|
strcpy(p,string); |-> 4.
strings[i] = p;----------------|
strings is an array of pointers, each pointer must point to valid memory.
Will lead undefined behavior since strings[i] is not pointing to valid memory.
Works but every pointer of strings will point to same location thus each will have same contents.
Thus create the new memory first, copy the contents to it and assign that memory to strings[i]
strcpy copies a particular string into allocated memory. Assigning pointers doesn't actually copy the string, just sets the second pointer variable to the same value as the first.
strcpy(char *destination, char *source);
copies from source to destination until the function finds '\0'. This function is not secure and should not be used - try strncpy or strlcpy instead. You can find useful information about these two functions at https://linux.die.net/man/3/strncpy - check where your code is going to run in order to help you choose the best option.
In your code block you have this declaration
char *strings[10],string[50],*p;
This declares three pointers, but they are quite different. *p is an ordinary pointer, and must have space allocated for it (via malloc) before you can use it. string[50] is also a pointer, but of length 50 (characters, usually 1 byte) - and it's allocated on the function stack directly so you can use it right away (though the very first use of it should be to zero out the memory unless you've used a zeroing allocator like Solaris' calloc. Finally, *strings[10] is a double pointer - you have allocated an array of 10 pointers, each element of which (strings[1], strings[9] etc) must be allocated for before use.
The only one of those which you can assign to immediately is string, because the space is already allocated. Each of those pointers can be addressed via subscripts - but in each case you must ensure that you do not walk off the end otherwise you'll incur a SIGSEGV "segmentation violation" and your program will crash. Or at least, it should, but you might instead get merely weird results.
Finally, pointers allocated to must be freed manually otherwise you'll have memory leaks. Items allocated on the stack (string) do not need to be freed because the compiler handles that for you when the function ends.

Memory allocation for pointer to a char array

would someone please explain the difference between
char *names[3]
and
char (*names)[3]
and how to read this operators?
If I want to allocate memory for them dynamically how to do so?
For the first case, I think it's just an array of char* of length 3, so no memory allocation not applicable. But in second case how to do memory allocation?
When faced with questions like this, you can usually turn to cdecl (online version here):
cdecl> explain char *names[3]
declare names as array 3 of pointer to char
cdecl> explain char (*names)[3]
declare names as pointer to array 3 of char
So the former creates array of three pointers-to-char:
+----------+
| names[0] | -> char
| [1] | -> char
| [2] | -> char
+----------+
And the latter creates a single pointer to a char array of size three.
+-------+
| names | -> char, char, char - no, not a dance step :-)
+-------+
The second line decodes as "declare names as pointer to array 3 of char".
I've been writing C for over 25 years, and I've never used such a variable.
Anyway, I guess this should work:
char data[3];
char (*names) = data;
Note that the variable name, names, is highly misleading since the variable holds only 3 single characters, as opposed to char *names[3] which is three pointers to characters and thus easily could be used to hold three strings.
Also note that the above code makes little sense, you could just use data directly if you had it.
The first an array of three pointers to char.
The second is a pointer to an array of three chars.
(Read it as "*names is a char[3]").
You can create such a pointer by taking the address of an array of three chars:
char name[3];
char (*names)[3] = &name;
or dynamically in the normal way:
char (*names)[3] = malloc(sizeof(*names)); /* or sizeof(char[3]), if you're fond of bugs */
or through the regular array-to-pointer conversion:
char stuff[2][3] = {};
char (*names)[3] = stuff; /* Same as &stuff[0], as normal. */
and how to read this operators?
Let's take the second one as it is the more complex of the two:
char (*names)[3];
When you are looking at a complex definition like this, the best way to attack it is to start in the middle and work your way out. “Starting in the middle” means starting at the variable name, which is names.
“Working your way out” means looking to the right for the nearest item (nothing in this case; the right parenthesis stops you short), then looking to the left (a pointer denoted by the asterisk), then looking to the right (an array of 3), then looking to the left (char).
This right-left-right motion works with most declarations.
This means names is a pointer to an char array of size 3.
This is very strange declaration but that is how it is read.
If I want to allocate memory for them dynamically how to do so?
Now that you know what the declaration means, memory allocation becomes easy:
char (*names)[3] = malloc(3 * sizeof(char));
char *names[3] is an array of 3 char pointers.
char (*names)[3] is an array pointer (pointer to array) to an array of 3 characters char[3].
So these two have fundamentally different meanings! Don't confuse them with each other.
If you wish to allocate an array of pointers, then you can do it as in either of these examples:
char** names = malloc(3 * sizeof(*names) );
char** names = malloc(sizeof(char*[3]));
char** names = calloc(3, sizeof(char*));
These are all equivalent (but calloc also sets all pointers to NULL). names will be a pointer to the first element in the array. It will be a pointer to a char*.
If you wish to allocate an array and point to the first element, simply do:
char* names = malloc(3 * sizeof(*names));
Alternatively, you can use the array pointer syntax and point to the array as whole:
char (*names)[3] = malloc(sizeof(*names));

Dynamically allocated 2 dimensional arrays

Does anyone know what the third line "Free(array)" does? array here is just the address of the first element of array(in other words, a pointer to the first element in the array of int * right)? Why do we need the third line to free the "columns" of the 2D array? I basically memorized/understand that a is a pointer to means a holds the address of ____. Is this phrase correct?
For example: int **a; int * b; int c; b = &c = 4;
a = &b; This is correct right? Thankyou!!!
Also, in general, double pointers are basically dynamically allocated arrays right?
"Finally, when it comes time to free one of these dynamically allocated multidimensional ``arrays,'' we must remember to free each of the chunks of memory that we've allocated. (Just freeing the top-level pointer, array, wouldn't cut it; if we did, all the second-level pointers would be lost but not freed, and would waste memory.) Here's what the code might look like:" http://www.eskimo.com/~scs/cclass/int/sx9b.html
for(i = 0; i < nrows; i++)
free(array[i]);
free(array);
Why do we need the third line to free the "columns" of the 2D array?
The number of deallocations should match up with the number of allocations.
If you look at the code at the start of the document:
int **array;
array = malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++) {
array[i] = malloc(ncolumns * sizeof(int));
}
you'll see that there is one malloc() for the array itself and one malloc() for each row.
The code that frees this is basically the same in reverse.
Also, in general, double pointers are basically dynamically allocated arrays right?
Not necessarily. Dynamically allocated arrays is one use for double pointers, but it's far from the only use.
Calls to malloc allocate memory on the heap, equal to the number of bytes specified by its argument, and returns the address of this block of memory. Your '2D array' is really a 1D array of int addresses, each pointing to a chunk of memory allocated by malloc. You need to free each of these chunks when you are done, making it available for others to use. But your 1D array is really just another malloc'd chunk of memory to hold these malloc'd addresses, and that needs to be freed also.
Also, when you use printf("%s", array) where array is an char *, the compiler sees the array as the address of array[0] but prints it right? I'm just curious if I'm understanding it right.
Yes, %s tells printf to go to whatever address you give it (an address of a char, aka a char*, let's say), and start reading and displaying whatever is in memory at that address, one character at a time until it finds a 'NULL character'. So in the case of a string, that is the expected behavior, since a string is just an array of chars, followed by the '\0' char.

Resources