This question was asked in the written round of a job interview:
#include<alloc.h>
#define MAXROW 3
#define MAXCOL 4
main()
{
int (*p)[MAXCOL];
p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p)));
}
How many bytes are allocated in the process?
To be honest, I did not answer the question. I did not understand the assignment to p.
Can anybody explain me what would be the answer and how it can be deduced?
It's platform dependent.
int (*p)[MAXCOL]; declares an pointer to an array of integers MAXCOL elements wide (MAXCOL of course is 4 in this case). One element of this pointer is therefore 4*sizeof(int) on the target platform.
The malloc statement allocates a memory buffer MAXROW times the size of the type contained in P. Therefore, in total, MAXROW*MAXCOL integers are allocated. The actual number of bytes will depend on the target platform.
Also, there's probably additional memory used by the C runtime (as internal bookeeping in malloc, as well as the various process initialization bits which happen before main is called), which is also completely platform dependant.
p is a pointer to an array of MAXCOL elements of type int, so sizeof *p (parentheses were redundant) is the size of such an array, i.e. MAXCOL*sizeof(int).
The cast on the return value of malloc is unnecessary, ugly, and considered harmful. In this case it hides a serious bug: due to missing prototype, malloc is assumed implicitly to return int, which is incompatible with its correct return type (void *), thus resulting in undefined behavior.
sizeof(*p) will be MAXCOL*sizeof(int). So totally MAXROW*MAXCOL*sizeof(int) number of bytes are alloctaed.
You might want to check out cdecl for help translating C declarations into English. In this instance, int (*p)[4]; becomes declare p as pointer to array 4 of int.
#include<alloc.h>
#define MAXROW 3
#define MAXCOL 4
main() {
int (*p)[MAXCOL];
p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p));
}
How many bytes are allocated in the process ?
p is a pointer, so will occupy sizeof(int(*)[MAXCOL]) on the stack, which might look daunting but it's almost always the same as sizeof(void*), sizeof(int*) or any other pointer. Obviously pointer sizes are what give applications their classification as 16-, 32-, 64-etc. bits, and this pointer will be correspondingly sized.
Then p is pointed at some memory obtained from malloc...
malloc( MAXROW * sizeof(*p) )
sizeof(*p) is the size of the int array that p points to, namely sizeof(int) * MAXCOL, so we get
malloc( MAXROW * (sizeof(int) * MAXCOL) )
requested from the heap. For illustrative purposes, if we assume the common 32-bit int size, we're looking at 48 bytes. The actual usage may be rounded up to whatever the heap routines feel like (heap routines often used fixed-sized "buckets" to speed their operations).
To confirm this expectation, simply substitute a logging function for malloc():
#include <stdio.h>
#define MAXROW 3
#define MAXCOL 4
void* our_malloc(size_t n)
{
printf("malloc(%ld)\n", n);
return 0;
}
int main()
{
int (*p)[MAXCOL];
p = (int (*)[MAXCOL]) our_malloc(MAXROW*(sizeof(*p)));
}
Output on my Linux box:
malloc(48)
The fact that malloc's returned pointer is cast to p's type doesn't affect the amount of memory allocation done.
As R sharply observes, lack of a malloc prototype would cause the compiler to expect malloc to return int rather than the actually-returned void*. In practice, it's probable that the lowest sizeof(int) bytes from the pointer would survive the conversion, and if sizeof(void*) happened to be equal to sizeof(int), or - more tenuous yet - the heap memory happens to start at an address representable in an int despite the size of pointers being larger (i.e. all the truncated bits were 0s anyway), then later dereferencing of the pointer just might work. Cheap plug: C++ won't compile unless it's seen the prototype.
That said, perhaps your alloc.h contains a malloc prototype... I don't have an alloc.h so I guess it's non-Standard.
Any program will also allocate memory for many other things, such as a stack frame providing some context within which main() may be called. The amount of memory for that varies with the compiler, version, compiler flags, operating system etc..
int (*p)[MAXCOL] == int (*p)[4] == "pointer to array 4 of int" (see Note below)
sizeof(*p) would then be what p points to, i.e. 4 * sizeof(int). Multiply that by MAXROW and your final answer is:
12 * sizeof(int)
Note: This is in contrast to:
int *p[MAXCOL] == int *p[4] == "array 4 of pointer to int"
The parentheses make quite a bit of difference!
It should be MAXROW*MAXCOL*sizeof(int) number of bytes
I really dislike questions like this, because I think it's far better as a working engineer to run the experiment than to assume that you know what you are doing - especially if there's reason for suspicion such as a program not working as expected or someone crafting trick questions.
#include <stdlib.h>
#include <stdio.h>
#define MAXROW 3
#define MAXCOL 4
main()
{
int (*p)[MAXCOL];
int bytes = MAXROW * (sizeof(*p));
p = (int (*)[MAXCOL]) malloc(bytes);
printf("malloc called for %d bytes\n", bytes);
}
On a 32 bit linux system:
gcc test.c
./a.out
malloc called for 48 bytes
(edited to remove pasting accident of multiplying by maxrow twice, yielding mistaken size of 144 bytes)
Running the following in codepad.org:
//#include<alloc.h>
#define MAXROW 3
#define MAXCOL 4
int main()
{
int (*p)[MAXCOL];
p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p)));
int x = MAXROW*(sizeof(*p));
printf("%d", x);
return 0;
}
prints out 48.
Why? Because MAXROW is 3, and sizeof(*p) is 16, so we get 3 * 16.
Why is sizeof(*p) 16? Because MAXCOL is 4, so p is a pointer to an array of 4 ints. Each int is 32 bits = 4 bytes. 4 ints in the array * 4 bytes = 16.
Why is sizeof(*p) not 4? Because it is the size of what p points to, not the size of p. To be the size of p it would have to be sizeof(p), which would be 4, as p is a pointer.
Pedantically you could add:
If the machine is 64 bit (say) the answer would be 96.
As the question states "How many bytes are allocated in the process?", you need to add the 4 bytes for the pointer p.
malloc can allocate more than you ask for (but not less) so the question cannot be answered.
In a similar vein as 2, you could argue that as the process is also loading system dlls such as the C runtime dll in order to run, it is allocating the space for those too. Then you could argue for the space allocated by dlls that are being injected into the process by other (non system) processes, such as those injected by Actual Window Manager and its ilk. But how pedantic do we want to get?
But I think the question is really asking for 48, with possible extra credit for explaining 96.
How about zero bytes because that won't even compile without the non-standard alloc.h. If you can't compile it, you can't run it and if you can't run it, it can't allocate any memory at all.
Related
#include <stdio.h>
int main(){
int a = 5;
int *p = &a;
int **pp = &p;
char **cp = (char **)pp;
cp++; // This still moves 8 bytes
return 0;
}
Since the size of a pointer is 64 bits on 64 bit machines, doing a pp++ will always move 8 bytes. Is there a way to make it move only 1 byte?
Is there a way to make it move only 1 byte?
Maybe.
All object pointers can be converted to void * and since char * has the same representation, to char *. ++ increments a char * by 1.
#include <stdio.h>
int main() {
int a = 5;
int *p = &a;
int **pp = &p;
char **cp = (char **)pp;
char *character_pointer = (char *) cp;
character_pointer++; // Increment by 1
Now is the tricky part. Can that incremented pointer convert back to a char **. C allows that unless
If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C17dr ยง 6.3.2.2 7
cp = (char **) character_pointer;
return 0;
}
Reading *cp can readily cause undefined behavior as cp does not certainly point to a valid char *. Unclear as to OP's goal at this point.
C is not assembly. What you are trying to do is undefined behavior, and compiler might not do what you ask, and the program might do anything, including possibly what you think it should do if C were just "assembly" with different syntax.
That being said, you can do this:
int a = 5;
int *p = &a;
int **pp = &p;
uintptr_t temp;
memcpy(&temp, &pp, sizeof temp);
temp++;
memcpy(&pp, &temp, sizeof temp);
Above code is likely to do what you want, even though that last memcpy already triggers undefined behavior, because it copies invalid value to a pointer (that is enough for it to be UB). Actually using pp, which now has invalid value, has increasing chance of messing things up.
To understand why having any UB is indeed UB: compiler is free to decide that the effect of the code, which can be proven to have UB, is nothing, or is never reached. So if that last memcpy is inside if, and compiler can prove UB occurs if condition is true, it may just assume condition is never true and optimize whole if away. Presumably C programmer knows to write their condition so that it would never result in UB, so this optimization can be made at compile time already.
Yeah, it is a bit crazy. C is not just assembly with different syntax!
Incrementing pointer to pointer by one byte
If you find an implementation where the size of a pointer to pointer variable contains only 8 bits, (i.e. one that uses 1 byte addressing, btw, very unlikely), then it will be doable, and only then would it be safe to do so. Otherwise it would not be considered a practical or safe thing to do.
For an implementation that uses 64 bit addressing, 64 bits are needed to represent each natural pointer location. Note however though _[t]he smallest incremental change is [available as a by-product of] the alignment needs of the referenced type. For performance, this often matches the width of the ref type, yet systems can allow less._ (per #Chux in comments) but de-referencing these locations could, and likely would lead to undefined behavior.
And in this statement
char **cp = (char **)pp; //where pp is defined as int **
the cast, although allowing a compile without complaining, is simply masking a problem. With the exception of void *, pointer variables are created using the same base type of the object they are to point to for the reason that the sizeof different types can be different, so the pointers designed to point to a particular type can represent its locations accurately.
It is also important to note the following:
sizeof char ** == sizeof char * == sizeof char *** !!= sizeof char`
32bit 4 bytes 4 bytes 4 bytes 1 byte
64bit 8 bytes 8 bytes 8 bytes 1 byte
sizeof int ** == sizeof int * == sizeof int *** !!= sizeof int`
32bit 4 bytes 4 bytes 4 bytes 4 bytes (typically)
64bit 8 bytes 8 bytes 8 bytes 4 bytes (typically)
So, unlike the type of a pointer, its size has little to do with it's ability to point to a location containing an object that is smaller, or even larger in size than the pointer used to point to it.
The purpose of a pointer ( eg char * ) is to store an address to an object of the same base type, in this case char. If targeting 32bit addressing, then the size of the pointer indicates it can point to 4,294,967,296 different locations (or if 64 bits to 18,446,744,073,709,551,616 locations.) and because in this case it is designed to point to char, each address differs by one byte.
But this really has nothing to do with your observation that when you increment a pointer to pointer to char that you see 8 bytes, and not 1 byte. It simply has to do with the fact that pointers, in 64bit addressing, require 8 bytes of space, thus the successive printf statements below will always show an increment of 8 bytes between the 1st and 2nd calls:
char **cp = (char **)pp;
size_t size = sizeof(cp);
printf("address of cp before increment: %p\n", cp);
cp++; // This still moves 8 bytes
printf("address of cp after increment: %p\n", cp);
return 0;
According to the answer from my faculty malloc dynamically allocates memory, Then why the output shows the same size allocated to both normal variable and malloc();. I am a newbie to programming, so I guess you would answer my question the way that a newbie can understand.
#include<stdio.h>
int main()
{
int a,b;
a = (int *) malloc(sizeof(int)*2);
printf("The size of a is:%d \n",sizeof(a));
printf("The size of b is:%d \n",sizeof(b));
return 0;
}
Output:
The size of a is:4
The size of b is:4
Malloc is used on a pointer. You are declaring an integer int a. This needs to be changed to int *a
The sizeof() operator will not give the no of bytes allocated by malloc. This needs to be maintained by the programmer and typically cannot be determined directly from the pointer.
For int *a, sizeof(a) will always return the size of the pointer,
int *a;
printf("%zu\n",sizeof(a)); // gives the size of the pointer e.g. 4
a = malloc(100 * sizeof(int));
printf("%zu\n",sizeof(a)); // also gives the size of the pointer e.g. 4
You should always remember to free the memory you have allocated with malloc
free(a);
Edit The printf format specifiers should be %zu for a sizeof() output. See comments below.
You declare and define both variables as int. Nothing else has an influence on the value of sizeof().
int a,b;
This assigns a value to one of those ints which which is very special, but it does not change anything about the fact that a remains an int (and your cast is misleading and does not do anything at all, even less to change anything about a).
a = (int *) malloc(sizeof(int)*2);
In order to change above line to something sensible (i.e. a meaningful use of malloc) it should be like this:
int* a;
a= malloc(sizeof(int)*2);
I.e. a is now a pointer to int and gets the address of an area which can store two ints. No cast needed.
That way, sizeof(a) (on many machines) will still be 4, which is often the size of a pointer. The size of what it is pointing to is irrelevant.
The actual reason for using malloc() is determined by the goal of the larger scope of the program it is used for. That is not visible in this artificially short example. Work through some pointer-related tutorials. Looking for "linked list" or "binary tree" will get you on the right track.
What programs which meaningfully use malloc have in common is that they are dealing with data structures which are not known at compile time and can change during runtime. The unknown attributes could simply be the total size, but especially in the case of trees, the larger structure is usually unknown, too.
There is an interesting aspect to note when using malloc():
Do I cast the result of malloc?
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p;
p = (int *)malloc(20);
printf("%d\n", sizeof(p));
free(p);
return 0;
}
On my 64-bit machine, 4 is printed as the size of p. I'm assuming this is because integers take up 4 bytes in memory, and p is an integer pointer. What if I was running a 32-bit machine? Also, what would happen if I replaced
int *p with double *p
and
(int *)malloc(20) with (double *)malloc(20)?
You are assuming wrong.
In printf("%d\n", sizeof(p)); you are not printing size of integer.You are printing here sizeof 'pointer to an integer' which is 4 bytes in your case.Most probably you will get same result on 32-bit machine.
Now about malloc, It allocates number of bytes and returns pointer to it.So same size of memory will be allocated even if you cast the pointer from int* to double*.
In pointers, It will take four bytes for all pointers.
So while you are checking with sizeof, even it is a character pointer it will give four bytes. If you need the value of that pointer use like this.
printf("%d\n", sizeof(p));// It will give the pointer size.
malloc is allocating the given bytes. And it will give equal to all the pointers. Then don't cast the result of malloc. Refer this link.
You have some misunderstanding let me point them,
p = (int *)malloc(20);
You are allocating memory of 20 bytes and malloc returns a void pointer and but compiler does the casting for you and (int *) is not needed. Even though you have a pointer to a double or an int it takes the same amount of bytes (In a 32bit system this merely for mapping 4GB memory space).
// Should this be 4 or 8?
printf("%d\n", sizeof(p));
This should be 8 on a x64 platform if your executable or the build is x64 only. I assume your build is 32bit and it returns 4.
Above printf has a wrong specifier. sizeof returns size_t and not an int. So correct form should be,
printf("%zu\n", sizeof(p));
Irrespective of whether 64-bit system or 32-bit system, size of a pointer variable is 4 bytes by default since 64-bit build settings also have Debug32 by default.
If we specifically change build settings on 64-bit, then the pointer variable can hold 8 bytes.
I'm assuming this is because integers take up 4 bytes in memory, and p is an integer pointer.
Your assumption is not correct ! To answer your doubt not only integer pointer take up 4 bytes.
int *ptrint;
char *ptrchar;
float *ptrfloat;
double *ptrdouble;
Here all ptrint, ptrchar, ptrfloat, ptrdouble takes 4 bytes of memory since it would be the address stored in that variable.
And if you replace int *p with double *p and (int *)malloc(20) with (double *)malloc(20) , the size would be still 4 bytes. I hope this ans cleared your doubts.
#include<stdio.h>
#include<stdlib.h>
#define MAXROW 3
#define MAXCOL 23
int main(){
int (*p)[MAXCOL];
p = (int (*) [MAXCOL])malloc(MAXROW *sizeof(*p));
return 0;
}
I need to know how many bytes will be allocated for the following code (for this p).
also, is the casting before the malloc adds/frees bytes that were allocated in the malloc if the size is different ?
Thanks.
sizeof(*p) is the size of an array of MAXCOL ints, or MAXCOL * sizeof(int).
So, the malloc call you present will allocate MAXROW * MAXCOL * sizeof(int) bytes.
About the cast : it will not impact how many bytes are allocated by the malloc call. In fact, it's completely unnecessary (and in this case without any effect), and is better left out.
p is a pointer to an array of int of length MAXCOL. And so sizeof(*p) is the size of an array of int of length MAXCOL. Hence MAXROW *sizeof(*p) is equal to MAXROW*MAXCOL*sizeof(int).
Casting of the return value of malloc is not needed since malloc returns void*. As a general rule, in C code, you should not cast the return value of malloc.
I think it depends on your architecture, if ints are 32 or 64 bits. Then as David says, is MAXROW times that size.
I just started working with C and came across a line of code I don't understand. Could someone explain what it does?
short int * work = (short int *) malloc(1000*16);
What don't you understand exactly? The code declares a short int* which is a pointer to one or more 16 bit (at least 16 bit) signed integers. It initializes it to a pointer returned by malloc, which is a chunk of memory large enough to fit 1000 * 16 bytes.
Now, why did they use 1000 * 16? I don't know. Typically you would allocate along the lines of num_elements * sizeof(element), i.e., num_elements * sizeof(short int).
More canonically, use num_elements * sizeof(*work) so that your code doesn't break if you change the type of the pointer.
Also note that it is a bad idea to cast the return value of malloc in C.
Let's break it down:
short int * work
This declares a pointer to an int, called work. It's declared as a short int, which means that it must be:
at least 16 bits in length (or two 8 bit bytes), and
not bigger than a plain int.
Generally, shorts are used when an int may be too large. Wikipedia has an excellent breakdown of C data types here: http://en.wikipedia.org/wiki/C_data_types
= (short int *) malloc(1000*16);
This allocates 1000*16 bytes, and assigns it to the pointer. You can read more about malloc() in the malloc() man page. This particular line is an example of bad style because:
It's unnecessary to cast the result of malloc - see Do I cast the result of malloc?
Because the size of a short int isn't defined in a standard, this line isn't guaranteed to produce any particular number of short ints.
It would be better to instead write:
short int * work = malloc(sizeof(short int) * NUMBER_OF_SHORT_INTS_REQUIRED);
or, even better:
short int * work = malloc(sizeof(work[0]) * NUMBER_OF_SHORT_INTS_REQUIRED);
Remember to check to make sure that malloc hasn't returned NULL before doing anything with work.
You are reserving (dynamically = on run-time) 1000 * 16 = 16000 bytes by using malloc. Using malloc what you get is a pointer to the address of the first byte of the 16000 bytes that have been reserved. You store the result to the pointer that you have for short integers named "work". Typically, every short integer has size 2 bytes, so, essentially malloc has reserved space for 8000 short integers (assuming it succeeded).
If malloc failed to allocate the space, it returns NULL.
Finally, it is bad practice to cast what malloc has returned.
Saw "declarations" in your title.
They have a very good web site for complex declarations. here