Array that points to another array - c

I'm new to C.
Create an array which holds at every index a pointer to another array of dynamic size.
int main()
{
unsigned int i , j;
int* array1[2];
int a1[] = {1,2,3};
int a2[] = {2,3};
array1[0] = a1;
array1[1] = a2;
for (i=0 ; i < 2; i++) {
printf(" the value of array1[%d] = %d" , i , *array1[i]);
}
return 1;
}
the value of array1[0] = 1
the value of array1[1] = 2
Only first elements are getting printed . How to print the whole array the index points to. What thing i'm missing.
EDITED ::
I now understand the use but similarly doing it directly , causing an array.
`unsigned int* c[3];
c[0] = {0, 5, 4, 7}; // This Line Err`
c[1] = {0, 5, 4, 3, 2, 6, 7};
c[2] = {0, 5, 4, 3, 2};
Causing an error : file try.c line xx function main: syntax error before `{'
Why ??
Thanks

As you know, array1[0] holds a pointer to the first element of a1 array; to print all elements of a1 array, you should iterate over it, something like this:
for (int i = 0; i < 2; i++){
printf(" the value of a1[%d] = %d", i, *(array1[0] + i);
}

An array is decayed to a pointer in C, in particular when passing it as argument (or storing it in a pointer).
What you are missing is that at runtime, the actual size of the array is not kept (and sizeof is a compile-time operator, replaced by the compiler by a constant - except for VLAs).
You might wish to keep the array size and its content together. Using a struct with a last flexible array member is a cute way to do that:
struct vect_st { unsigned size; int flexarr[]; };
struct vect_st* arr1[2];
Such structures need to be heap allocated (because you know their real size only at runtime):
arr1[0] = malloc(sizeof(struct (vect_st) + 2*sizeof(int));
if (!arr1[0]) {perror("malloc arr1[0]"); exit(EXIT_FAILURE); };
arr1[0]->size = 2;
arr1[0]->flexarr[0] = 4;
arr1[0]->flexarr[1] = 17;
arr1[1] = malloc(sizeof(struct (vect_st) + 3*sizeof(int));
if (!arr1[1]) {perror("malloc arr1[1]"); exit(EXIT_FAILURE); };
arr1[1]->size = 3;
arr1[1]->flexarr[0] = 5;
arr1[1]->flexarr[1] = 6;
arr1[1]->flexarr[2] = 7;
OF course, you should release the memory when you don't need it, so you'll probably end your main with code like
free(arr1[0]), arr1[0] = NULL;
free(arr1[1]), arr1[1] = NULL;
Beware of memory leaks, buffer overflows and other undefined behavior. So compile your code with all warnings & debug info (gcc -Wall -Wextra -g) and use valgrind and the gdb debugger.
Notice also that you should usually not declare non-small arrays (or aggregates) as local data (e.g. some local int biglocarr[1000000]; inside your main or some other function), since the call stack is limited in size (typically to a few megabytes, so no more than a few hundred bytes per call frame). Read about stack overflows and avoid them.

You are using *array1[i] , here " * " means pointer and value at array1[i] and i is 0 in first case, so it is pointing to a1 base, i.e. 1 and so on..

Related

Arrays in C. How sizeof() works, where I can find its declaration, how an array is actually created and where I can find that source code as well

How does sizeof() calculate that array1 is 3 bytes instead of 4 since I assigned a value to the 4th byte of memory allocated to the array?
#include <stdio.h>
char array1[3] = { 0,0,0 };
char array2[4] = { 0,0,0,0 };
char* a1 = array1;
char* a2 = array2;
int main(void) {
printf("Array 1 Memory: %p\n", a1);
printf("Array 2 Memory: %p\n\n", a2);
//Array 1 set values and display addresses.
printf("array1 = [");
for (int i = 0; i < 5; i++) {
array1[i] = i;
printf("%d, ", array1[i]);
}
printf("\n");
for (int i = 0; i < 4; i++) {
printf("array1[%d] memory location: %p\n",i, a1 + i);
}
printf("size of array1 = %d\n", sizeof(array1));
printf("]\n");
//Array 2 display values and addresses
printf("array2 = [");
for (int i = 0; i < 4; i++) {
printf("%d, ", array2[i]);
}
printf("\n");
for (int i = 0; i < 4; i++) {
printf("array2[%d] memory location: %p\n", i, a2 + i);
}
printf("size of array2 = %d\n", sizeof(array2));
printf("]\n");
printf("array2[-1] = %d\n", array2[-1]);
return 0;
}
Array 1 Memory: 005CA4F4
Array 2 Memory: 005CA4F8
array1 = [0, 1, 2, 3, 4,
array1[0] memory location: 005CA4F4
array1[1] memory location: 005CA4F5
array1[2] memory location: 005CA4F6
array1[3] memory location: 005CA4F7
size of array1 = 3
]
array2 = [4, 0, 0, 0,
array2[0] memory location: 005CA4F8
array2[1] memory location: 005CA4F9
array2[2] memory location: 005CA4FA
array2[3] memory location: 005CA4FB
size of array2 = 4
]
array2[-1] = 3 //3 is stored in this location, so all bytes in the 4 byte word have a value in them. So
//how does sizeof(array1) return a value of 3 instead of 4. How does it "remember" that only 3 bytes were
//originally assigned to the array?
I looked for the declaration for the sizeof function in stdio header and couldn't find it. I thought that if I could see how sizeof() determines the size of an array, then it would give me some insight to my question. I'd like to know where sizeof() can be found.
Where is the source code for the C compiler that I can refer to in order to learn what an array actually is and how its size is stored in memory? If I create a char array[3], then a char[3] object is created, right? How is the char[3] object created? How does the system "remember" that the array should only be 3 bytes?
Some useful links (highly recommended):
sizeof operator
Queries size of the object or type
Used when actual size of the object must be known
In C, there is no object creation per se but a definition of an declared object, more here:
Declarations
A declaration is a C language construct that introduces one or more identifiers into the program and specifies their meaning and properties.
Definitions
A definition is a declaration that provides all information about the identifiers it declares.
and
Array declaration
Array is a type consisting of a contiguously allocated nonempty sequence of objects with a particular element type. The number of those objects (the array size) never changes during the array lifetime.
and
Array initialization (e.g. Initialization from brace-enclosed lists)
sizeof(array1) tells you how many bytes of memory were reserved for the object array1. It does not tell you how many bytes you attempted to store into it.
char array1[3] = { 0,0,0 }; reserves three bytes for array1.
array1[i] = i; attempts to write a byte to array1[i]. The C implementation generally does not check whether you are staying within the reserved memory or not. If you do not stay within the memory reserved for the array, the behavior is not defined by the C standard.
Using array1[i] = i; to write to memory outside the array does not change the reservation.
A source of confusion for beginners is seeing sizeof() with parentheses and presuming it is a runtime function. It is not a runtime function. It is a "compile time" operator.
Parentheses are required when taking the size of a datatype:
eg: sizeof( char ) or sizeof( struct foobar ).
Parentheses are optional when taking the size of an item the compiler has already "seen" in the current "compilation unit" (typically meaning the current source file being compiled.) For example:
double a;
size_t size_of_a = sizeof a; // parentheses not required here.
Imagine that the expression "sizeof a" above is replaced with the value 8 (being the number of bytes used to store a single double floating point number in many compilers.)
The compiler has had to "measure" the storage requirements for your array. During compilation, the compiler "knows" the extent of that allocation and can quickly replace sizeof myarray with the correct value.

Dynamic memory allocation vs Using pointer

im new to the C language and im trying to understand the basic of memory allocation .
here I have two function that produce the exact same result, but only one of them using the malloc() function and the other one is not.
FIRST FUNCTION
int First()
{
int arr[] = {11, 13, 7, 12, 16};
int length = sizeof(arr) / sizeof(int);
// NOT using malloc
int arr2[length];
// Initialize elements to 0
for (int i=0; i < length; i++)
arr2[i] = 0;
// Print results
for (int i = 0; i < length; i++)
printf("%d ", arr2[i]);
return 0;
}
SECOND FUNCTION
int Second()
{
int arr[] = {11, 13, 7, 12, 16};
int length = sizeof(arr) / sizeof(int);
int *arr2;
// Here im using malloc to allocate memory
arr2 = malloc(sizeof *arr2 * length);
// Initialize elements to 0
for (int i=0; i < length; i++)
arr2[i] = 0;
// Print results
for (int i = 0; i < length; i++)
printf("%d ", arr2[i]);
return 1;
}
Both of this two functions will print: 0 0 0 0 0.
What are the differences between this two approaches ? I know that using malloc(or memset) to allocate memory based on a variable is the right approach , but im trying to understand why exactly ?
Thanks!
The difference is the lifetime of the objects. Basically it means when the object is valid and it can be accessed.
Generally, there are three lifetime types:
Static
The object is valid all the time
Example:
int* foo(void) {
static int A[10];
return A;
}
Array A is always valid. It can be safely returned from a function.
Automatic
The object is valid from its definition to end of the block where it was declared
Example:
void foo(void) {
int *p;
{
int A[10];
... A is valid here ...
p = &A[0]; // p points to
*p = 42; // still valid
}
// A is no longer valid
*p = 666; // UB strikes, expect everything
}
A pointers to automatic objects should never be returned from functions because they would point to non-existing objects. Any use of value of such a pointer triggers Undefined behavior.
Dynamic
The lifetime is controlled by the program. It starts with memory allocation via malloc() or similar functions. It ends when calling free() on the pointer to this object. Dynamic object can only be accessed via a pointer.
Example:
int* foo(void) {
int *p;
{
p = malloc(sizeof(int[10])); // p points to an object for 10 ints
*p = 42; // still valid
}
*p = 43; // still valid
return p; // still valid though function has returned
}
int *p = foo();
*p = 44;
free(p); // release
*p = 666; // UB strikes, expect everything
Forgetting to call free() usually leads to the memory leak.
The second function has a memory leak because the dynamically allocated array was not freed.
The first function is conditionally supported by compilers due to using a variable length array. Also if the size of the array is big then it can occur such a way that the array will not be allocated.
And the function memset allocates nothing.
One of the differences that I can come up with is the sizes of the arrays.
In your first function, if you put sizeof(arr2) at the end, you will get 20. But at your second function, when you put sizeof(arr2) you will get 8. (Size of a pointer depends on your computer. A pointer's size is 8 bytes in 64-bit mode. And 4 bytes in 32-bit mode.)

Assigning the value of a pointer at a certain index in C

I'm trying to understand this code:
struct mys {
double d[128];
};
void my_func(int iters) {
int i;
struct mys *ptr = malloc(iters *sizeof(struct mys));
for(i = 0; i < iters; i++) {
ptr[i].d[0] = (double)i;
}
free(ptr);
}
What I know:
mys is of size 8 * 128 (size of double is 8, it's an array of 128 doubles)
*ptr is of size iters * (8 * 128)
What is going on here:
ptr[i].d[0] = (double)i;
?
What I know:
// ptr->d is the address of the first part of d
// same as (*ptr).d
// BECAUSE d IS A STRUCT
// ptr->d[i] is the actual value. so, 0.0000
// same as (*ptr).d[i]
Thanks in advance.
ptr[i] is the value at index i, so starts at 0.0000.
d is not initialized, it is just the name of the member of a struct. How can we just d here?
What I think:
*ptr is multiple (iters) structs.
So, ptr[0] is the first struct, ptr[1] is the second struct, etc.
ptr[i].d access the ith struct's d array.
ptr[i].d[0] accesses the first index of the d array. So the line above sets that number to double(i).
So this really only sets the first element of each struct to be 0. Am I right?
But when iters is 2, and I try:
for(int i = 0; i < iters; i++) {
printf("%p\n", ptr[200].d);
}
it still prints an address. Why is that?
What is going on here: ptr[i].d[0] = (double)i;?
This:
struct mys *ptr = malloc(iters *sizeof(struct mys));
allocates memory for an array of structs, called ptr.
This line of code:
ptr[i].d[0] = (double)i;
assigns i to the first cell of the array d, of the i-th struct, in the array ptr.
i is casted to double, because d is an array of doubles, and i is declared as int.
when iters is 2, and I try: for(int i = 0; i < iters; i++) { printf("%p\n", ptr[200].d); } it still prints an address. Why is that? Shouldn't it be out of range since ptr is only 2 structs?
This is definitely out of range, since arrays are 0-indexed.
However, that attempt invokes Undefined Behavior (UB), which means that you don't know how the code is going to behave. For example, in your computer it prints an address, in my computer it might cause a segmentation fault, and so on...
So this really only sets the first element of each struct to be 0. Am I right?
It copies the index i, converted to type double, into the first element of each struct. Otherwise you are right.
Regarding the expression ptr[200].d, this is the same as &(ptr[200]) because the array d[] is the sole element of a mys object. Because a double is eight bytes wide, each mys object occupies (8 bytes)(128) = 1 kiB. Therefore, &(ptr[200]) == ptr + 200*1024. The last is an address 200 kiB past the beginning of *ptr. Whether the address has meaning depends on whether anything meaningful is stored there.

Why can't I use malloc to set array size larger than what is needed?

I am coming from Python so using malloc is new to me. Intuitively the below should work but having syntax issues. In my first line I want to set array size to be a max of 8 ints. In the second line, I want to add those 4 ints. This line is for example only, in production I will have user input up to an 8-digit number. When I go to compile (clang) I get size of array has non-integer type 'void *' If I comment out this first line and initialize with the second line (and adding int type) the code works. So I am obviously setting the size incorrectly. Any ideas?
int main(void)
{
int mult_digits[malloc(8 * sizeof(int))];
mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof *mult_digits;
printf("Size of the array is %d\n", size_mult);
return 0;
}
This code is all wrong. You call malloc to allocate memory, and malloc returns a pointer. Rather than deconstructing your syntax, which is very broken, I'll give a couple of variants of your program.
int main(void)
{
int mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof *mult_digits;
printf("Size of the array is %d\n", size_mult);
return 0;
}
Here the array is not allocated dynamically. It's a local variable with automatic, stored on the stack.
For dynamic allocation you would do this:
int main(void)
{
int *mult_digits = malloc(4*sizeof *mult_digits);
mult_digits[0] = 1;
mult_digits[1] = 2;
mult_digits[2] = 3;
mult_digits[3] = 4;
free(mult_digits);
return 0;
}
The argument to malloc is the number of bytes to be returned. The value returned is the address of the new block of memory. Note also here that we made a call to free to deallocate the memory. If you omit that, the memory will be leaked.
With this variant, there is no way to recover the length of the array from mult_digits. I know that might freak you out, coming from Python, but I repeat. There is no way to recover the length of the array from mult_digits. It's your job to keep track of that information.
Now, you wanted to over-allocate the memory. You can certainly do that:
int main(void)
{
int *mult_digits = malloc(8*sizeof *mult_digits);
mult_digits[0] = 1;
mult_digits[1] = 2;
mult_digits[2] = 3;
mult_digits[3] = 4;
free(mult_digits);
return 0;
}
Here we only used the first 4 elements, and ignored the final 4. That's just fine. In case you do over-allocate you would typically need to keep track of both the allocated length, and the in-use length. You can then add new items by increasing the in-use length, up until you reach the allocated length. The you need to reallocate a larger block. I guess that's what you are driving at.
The problem is your syntax. What you meant was: int *mult_digits = malloc(8 * sizeof(int));
After that, mult_digits[] = {1,2,3,4}; is wrong. You could, however,
mult_digits[0] = 1;
mult_digits[1] = 2;
mult_digits[2] = 3;
mult_digits[3] = 4;
But unless you have some reason to swim into the pointer deep end, you might just want to:
int mult_digits[] = {1, 2, 3, 4};
Edit: to help with applying this answer, here is a full modified function that compiles and runs:
#include <stdio.h>
int main(void)
{
int mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof *mult_digits;
printf("Size of the array is %d\n", size_mult);
return 0;
}
in square brackets you must specify the number of elements needed, not the length in byte of the array. you can use malloc to do
int* multdigits = malloc(sizeof(int)*8);
mult_digits[0] = 1;
etc
(sorry if my syntax is wrong, i don't write c code from years!)
they're two ways to do the same thing. see "malloc" as the "new" operator.
Try
int main(void)
{
int mult_digits[] = {1,2,3,4};
int size_mult = sizeof mult_digits / sizeof int;
printf("Size of the array is %d\n", size_mult);
return 0;
}

Concatenating 2 arrays without memcpy

Suppose I ve
int *a,*b;
a= malloc(5*sizeof(int));
b= malloc(5*sizeof(int));
and subsequently assign values.
Let a - 1, 2, 3, 4, 5
b - 6, 7, 8, 9, 10
Is there a method to concatenate both these malloced arrays without using further malloc,realloc or memcpy? There shud not be a malloc of 10 locations!
I must be able to get a[8]=9 after executing, without the overhead of moving the arrays.
The language is C
a= malloc(5*sizeof(int));
You only allocated 5 ints to a, so no, you can't do it without some form or memory allocation (malloc / realloc), since a[8] would be illegal to begin with.
I must be able to get a[8]=9 after executing, without the overhead of
moving the arrays
Since since you are working with contiguous memory regions (which you are calling arrays) you will always have some overhead when moving elements around. If you don't need to access elements by their indexes just use linked lists.
If you don't need strict array indexing, you could make a pseudo-linked-list (I know there's a name for this data type but I can't remember it right now):
struct listish {
int *arr
size_t size;
struct listish *next;
};
The "indexing" function would look like this:
int *index(struct listish *list, size_t i)
{
if(list == NULL) return NULL; // index out of bounds
if(i < list->size) return list->arr + i; // return a pointer to the element
else return index(list->next, i - list->size); // not in this array - go to next node
}
The idea is to combine the in-place reordering of a linked list with the contiguous space of an array. In this case, index(list, 4) would return &a[4], and index(list, 5) would return &b[0], simulating continuous indexing without reallocating and moving your entire array - all you need to do is allocate a few small struct listish objects and set them up properly, a task I leave to you.
What you ask can't be done.
You have, maybe, another option.
Just allocate space for 10 values, and make b point to the correct element
int *a = malloc(10 * sizeof *a);
/* error checking missing */
int *b = a + 5;
a[0] = 1; a[1] = 2; a[2] = 3; a[3] = 4; a[4] = 5;
b[0] = 6; b[1] = 7; b[2] = 8; b[3] = 9; b[4] = 10;
printf("a[8] is %d\n", a[8]);

Resources