2

I am trying to learn dynamic memory allocation and structures and I have some questions.

First of all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int *number;
    number = malloc(1*sizeof(int));
    int a;
    for(a=0;a<150;a++)
    {
        number[a]=a;
        printf("%d ",number[a]);
    }
    return 0;
 }

In this sample I planned it to give me error. Because I allocated it to size of 1 integer, then I wrote it way too much integers. Shouldn't it give me an error? Can you explain this with detail please?

struct people 
{
    char *name;
    int age;
    char *personalInfo;
} human[3];

When I define a structure like this, how can I allocate it to keep more than 3 human? How can I change it to something like human[20] or more? In case if the answer is writing *human instead of human[3], how should I allocate it? Like malloc(number*sizeof(char)*sizeof(int)*sizeof(char))?

And one more thing, in second example do I need to allocate name and personalInfo pointers?

Fiddling Bits
  • 8,712
  • 3
  • 28
  • 46
ossobuko
  • 851
  • 8
  • 25
  • 3
    You're invoking **undefined behavior** in your first sample, so assuming *anything* is officially off the table. – WhozCraig Jan 02 '14 at 16:36
  • 4
    Note: DMA is more commonly used as acronym for Direct Memory Access, so using it to mean dynamic memory allocation is likely to cause confusion. – hyde Jan 02 '14 at 16:38
  • 3
    `malloc(number*sizeof(char)*sizeof(int)*sizeof(char))` -- **No.** Just think about that. It doesn't make sense. If you put an `int` and a `char` next to each other, will the total size be the product of their sizes? Of course it won't -- it will be the sum of their sizes, so `malloc(number* (sizeof(char)+sizeof(int)+sizeof(char)))` would make more sense. **However, that would be still wrong and dangerous,** because the struct can contain internal padding, so you'd better off writing `sizeof(the_struct_name)`. –  Jan 02 '14 at 16:43
  • 1
    @hyde Thanks for mentioning that. I was confused. – Fiddling Bits Jan 02 '14 at 17:17

5 Answers5

6

In this sample i planned it to give me error.

You can't "plan to give an error". You're correct to say that the code is wrong because you are writing past the end of the array, but C has no bounds checking -- accessing the array is simply undefined behavior, which means that it can do literally anything -- it can pretend to work fine or it can crash, or it can cause demons to fly out of your nose.

How can i change it to something like human[20] or more?

Well... that's exactly how:

struct people {
   // members here
} human[20];

I don't see why the number "3" is so special. If you want to allocate memory dynamically, you would do it the way you would do in the case of every other data type: use the sizeof operator:

struct people *human = malloc(sizeof(human[0]) * number_of_people);

or

struct people *human = malloc(sizeof(struct people) * number_of_people);
  • 1
    Note (to comfort any 4 year old reader) that although the demon rhinology example is common, the computer does not actually have the ability to have any influence on supernatural beings in your sinuses. – William Pursell Jan 02 '14 at 16:39
  • 2
    @WilliamPursell: the computer could be an embedded device inside a pharmaceutical drug factory.... So it could make real damage to sinuses (by some uncontrolled release of dangerous substances). – Basile Starynkevitch Jan 02 '14 at 16:47
  • @BasileStarynkevitch Never had I encountered such a clever defense of the "UB can do anything" argument! :P –  Jan 02 '14 at 16:48
  • 1
    @H2CO3: In practice, it is a bit more complex; in several industrial standards (DOI178C, ISO26262 at ASIL D, ....) for somehow critical embedded software `malloc` is simply *forbidden* (but some undefined behavior *could* happen). – Basile Starynkevitch Jan 02 '14 at 16:50
  • @BasileStarynkevitch Well, thinking about it a bit, until UB cannot be detected somehow (which it can't really, that's why it is undefined), one has no real chance to make sure a program is perfect. –  Jan 02 '14 at 16:51
  • 1
    @H2CO3: I definitely agree. However, I feel a bit safer when climbing into an Airbus knowing that quite latest static analysis techniques (see [ASTREE](http://en.wikipedia.org/wiki/Astr%C3%A9e_%28static_analysis%29)...) have been applied. But it is *not* a silver bullet. See [J.Pitrat's blog](http://bootstrappingartificialintelligence.fr/WordPress3/) for an alternative (and futuristic) approach. – Basile Starynkevitch Jan 02 '14 at 16:54
  • @BasileStarynkevitch Yeah, sure, and honestly, I don't know whether I would dare to fly on an airplane of which I've written the controlling software. And not because I'm a bad programmer... I'm just not perfect. Ugh. Scary. –  Jan 02 '14 at 16:56
  • @H2CO3; If so, then please inform us whenever you write the controlling software. We will take some precautions :) – haccks Jan 02 '14 at 17:02
  • Man! You are looking like prophet Isaah (Jesus) :P – haccks Jan 02 '14 at 17:42
  • @haccks :D Actually, Stallman is *kind of* a god in computer science. –  Jan 02 '14 at 17:42
  • OK. Now here is second one -;). I like this avatar. – haccks Jan 02 '14 at 17:47
  • Do you mind explaining to me in which cases when i give values to pointer strings it becames undefined behavior? I am really confused on the relation between pointers and ub. Do i have to allocate it everytime i gave a value to a pointer string? – ossobuko Jan 02 '14 at 19:50
  • @OssoBuko If you attempt to **write** to a string literal, that results it undefined behavior. That is, `char *s = "foo"; s[0] = 'b';` leads to undefined behavior. (This is why it is advisable to declare a pointer to string literal as `const char *`). If, however, you write to a string that is writable (such as a non-const array), you can do that of course, it's legal. –  Jan 02 '14 at 19:58
4

C does not provide compile-time or run-time bounds checking of arrays. The program must perform its own bound checking. If you write beyond the end of an array, your program will have undefined behavior. In practice it means that you're corrupting your process' memory by writing to uninitialized areas or areas that are used by allocators for bookkeeping. This can cause the program to crash immediately, crash on exit, or can overwrite the values of other (possibly unrelated) variables in the heap.

To allocate a variable number of people structures, you can do this:

struct people *humans;
humans = malloc(N * sizeof(struct people));
// humans now points to an array of N `people`

For your last question, yes, you must allocate space for those strings, unless you're simply using those pointers to point to strings defined/allocated elsewhere. Note this means that even in the code above where I allocate N objects, I still haven't allocated any space for the strings, and can't write to them until I do so.

TypeIA
  • 16,916
  • 1
  • 38
  • 52
3
struct people 
{
  char *name;
  int age;
  char *personalInfo;
};

struct people *human;

human = malloc(sizeof(*human) * 20);
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
1

In this sample i planned it to give me error. because i allocated it to size of 1 integer, then i wrote it way too much integers. Shouldn't it give me an error? Can you explain this with detail please?

No, it shouldn't. This is undefined behavior, which may lead to a crash at runtime, but the compiler will neither warn you about it nor produce any errors. You can detect errors like this by running your program in a memory profiler, such as valgrind.

When i define a structure like this, How can i allocate it to keep more than 3 human? How can i change it to something like human[20] or more?

Like this:

struct people *human = malloc(20 * sizeof(struct people));

Like malloc( number*sizeof(char)*sizeof(int)*sizeof(char) ) ?

Besides being too inconvenient, adding up sizes of individual fields may not produce the correct size, because the compiler is allowed to pad your struct to optimize access to its fields. That is why you need to use sizeof(struct people).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • "adding up sizes of individual fields may not produce the correct size" -- even less would multiplying them do so (I'm wondering where OP got that idea -- it just doesn't make sense.) –  Jan 02 '14 at 16:49
1

The first example invokes undefined behavior.

§6.5.6/8: If both the pointer operand and the result point to elements of the same array
 object, or one past the last element of the array object, the evaluation shall not 
produce an overflow; otherwise, the behavior is undefined

If you want to allocate for 20 humans, you can do...

typedef struct people 
{
    char *name;
    int age;
    char *personalInfo;
}People;

People *human;

human = malloc(sizeof(*human) * 20);