2

Consider the following code in C.

char *s = malloc(5);

I prompted the user for 4 char input and stored it in *s. While the program is working with the string s it may know that it is at the end of the string by encountering a '\0'.

Now , my problem is:
How does the compiler get to know that it is at the end of the array i in the following code?

int *i = malloc(5);
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Nitesh_Adapa
  • 133
  • 7
  • 13
    It doesn't. In C, this is the responsibility of the programmer. – Thomas Mar 12 '18 at 11:28
  • 1
    its just a pointer, after 5 elements it will point to something else – Tuấn Phạm Mar 12 '18 at 11:28
  • 1
    @TuấnPhạm if by "something else" you mean "Undefined Behavior" then yes, else no... – bolov Mar 12 '18 at 11:37
  • Ok,it is up to the programmer to make sure that it isn't going out of the bounds.Then,why the '\0' is given for checking the end of a string??..I'm a beginner .... – Nitesh_Adapa Mar 12 '18 at 11:46
  • @Comp_sci_student The null terminator is only for strings specifically. For plain arrays, one has to use a separate size counter variable. – Lundin Mar 12 '18 at 11:56
  • regarding: ``int *i = malloc(5);` this is defining/allocating 5 bytes from the heap. that 5 bytes is declared to be a pointer to an integer. So the statement is incorrect. It should be: `int *i = malloc( sizeof( int* ) );` or `int *i = malloc( sizeof( i ) );` – user3629249 Mar 13 '18 at 16:50

5 Answers5

9

It doesn't (have to) know.

In C, the compiler need not know whether you are indexing out-of-bounds, or are otherwise invoking Undefined Behavior (UB), it will simply take you at your word.
Lying to it will have interesting consequences, especially as the more optimization you request, the harder it will try to prune the invalid paths. The fastest code is code which isn't there.


Now, looking at the specific example of how to determine the size of some memory, C strings aren't a data-type, they are a data-format. Specifically, they are defined as a 0-terminated sequence, which includes the terminator. Whether you have a string, or how you determine what a pointer points to, is up to you.

And as an aside, doing a blanket allocation of 5 bytes for an int-array raises a red flag. An int is likely bigger than a byte, depending on your implementation. Consider using sizeof to ask for space for the number of int's you want instead.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
4

It doesn't. C does not do bounds checking of arrays. It is up to you as a programmer to ensure you do not access out of bounds data. Doing so results in undefined behaviour (aka bad things).

melpomene
  • 84,125
  • 8
  • 85
  • 148
doron
  • 27,972
  • 12
  • 65
  • 103
1

To be very clear: after saying

int *p1 = malloc(5);

if you then say

p1[0] = 1;

you are probably okay, if on your machine type int is 32 bits (4 bytes) or less. But if you say

p1[1] = 2;

you are probably not okay: you have probably written to bytes 4-7 of the malloc'ed region, i.e. more than you asked for, and you have committed undefined behavior. Anything might happen: you might store that value 2 without causing any other problems, you might overwrite some other variable or data structure (leading to subtle and difficult-to-diagnose bugs), you might get an immediate segmentation violation or other memory access error, you might corrupt memory in such a way that you get a segmentation violation or other memory access error some time later (which is a very difficult-to-diagnose bug). What you will almost certainly not get is a nice, clear error saying "array overflow".

It's a little easier to explain with a slightly more appropriate allocation. If you say

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

then p2[0] = 1 is fine, and p2[4] = 5 is fine, but p2[5] = 6 is undefined behavior. Or if you say

char *p3 = malloc(5);

then p3[0] = '1' is fine, and p3[4] = '5' is fine, but p3[5] = '6' is undefined behavior.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
0

Although the answers here are correct, and this may be not exactly what you asked, I want to add that there is some kind of book-keeping.When writing int *i=malloc(5);, somewhere behind the scenes, the length of the array is saved, so you would be able to call free(i) without specifying its length.

Note that, in your example, you can store 5 char inside the malloc-ed space, and then you wouldn't know the string has ended. Basically, when using arrays and malloc, it's your responsibility as the coder, to not go out-of-bounds

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • Well, there generally is such for a general-purpose-allocator. But it's a valid (and sometimes very advantageous) choice to chuck that and make `free()` a no-op, provided the amount of memory which might be re-purposed before program termination is adequately small. – Deduplicator Mar 12 '18 at 12:27
  • Not sure I understood, are you suggesting to ignore `free` for small memory allocations? – CIsForCookies Mar 12 '18 at 12:34
  • I'm saying that accepting the overhead neccessary to be able `free` allocated memory is not worthwhile in all cases, just like `free`-ing memory just before exiting is useless make-work. – Deduplicator Mar 12 '18 at 15:34
  • Oh, sure. Nevertheless, the overhead exists – CIsForCookies Mar 12 '18 at 15:54
  • Unless it doesn't, because you omit the feature. – Deduplicator Mar 12 '18 at 21:15
0

The best thing to do, is to save the size of your int array to parse it.

 #define ARRAY_SIZE 10

 int *array = (int *)malloc(sizeof(int) * ARRAY_SIZE));
 int i = 0;
 while (i < ARRAY_SIZE)
 {
     printf("%d\n", array[i]);
     i++;
 }
Damien Christophe
  • 115
  • 1
  • 1
  • 10