tags:

views:

120

answers:

3

I have the following assignment:

Write a function in C that allocates block of memory and returns a pointer to the start of the memory under these conditions:

  1. All addresses in the block are divisible by 32
  2. Allocated at least the number of the bytes required
  3. Every cell in the block is initialized to zero
  4. No global variants, minimum complexity

Write another function that also releases the memory that you allocated. (You know that the aforesaid memory was allocated by the first function that you just wrote ).

Here is a debugging temporary solution:

"aligned_malloc.h":

#ifndef  __ALIGNED_MALLOC_H__
#define  __ALIGNED_MALLOC_H__

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

#define ALIGNMENT 16

#if ALIGNMENT > 255
#error "This 'void *aligned_malloc(size_t size)' function can only handle alignment < 256"
#endif

#if ALIGNMENT < 0
#error "This 'void *aligned_malloc(size_t size)' function can only handle a non negative alignment"
#endif

void* aligned_malloc(size_t size);
void aligned_free(void *aligned_p);

#endif /* __ALIGNED_MALLOC_H__ */

"alligned_malloc.c":

#include "aligned_malloc.h"

#undef  DEBUG
#define DEBUG 1

int main()
{
    size_t size = 0;
    void *memblk = NULL;

    do while (size > 0 )
    {
        printf("\nPlease enter in bytes the memory block size you want to allocate (0 to exit): ");
        scanf("%d", &size);
        memblk = aligned_malloc(size);

        #ifdef     DEBUG
            printf("%s[%d]: memblk = 0x%x\n", __FUNCTION__, __LINE__, memblk);
        #endif  /* DEBUG */

    }

    if (memblk != NULL)
        aligned_free(memblk);

    return 0;
}

void *aligned_malloc(size_t size)
{
    int i = 0;
    void* memblk = malloc(size + ALIGNMENT);
    printf ("\n%ld",(long)memblk);

    //offset is the start address of memblk (long=8digit) modulo the ALIGNMENT
    unsigned char offset = ALIGNMENT - ((long)memblk % ALIGNMENT);
    printf ("\n%d",offset);

    if (memblk == NULL)
        return NULL;
    /* O/W: */  
    #ifdef     DEBUG
    printf("%s[%d]: memblk = 0x%x\n", __FUNCTION__, __LINE__, memblk);
    #endif  /* DEBUG */
    for (i = offset; i < size + ALIGNMENT; i++) 
    {
        printf("%02d: %08d\n", i, memblk+i);
        memblk[i] = 0;
    }

    *(memblk + offset - 1) = offset;

    return (void*)(memblk + offset);
}

void aligned_free(void *aligned_p)
{
    unsigned char offset = (unsigned char)(*((unsigned char *)aligned_p-1));
    #ifdef     DEBUG
    printf("%s[%d]: offset = %d\n", __FUNCTION__, __LINE__, offset);
    printf("%s[%d]: aligned_p-1 = 0x%x\n", __FUNCTION__, __LINE__, (unsigned char *)aligned_p-1);
    printf("%s[%d]: aligned_p-offset = 0x%x\n", __FUNCTION__, __LINE__, aligned_p-offset);
    #endif  /* DEBUG */
    free(aligned_p-offset);
}

Now I have several problems here:

  1. There is a compilation error in main()
  2. I cannot catch how to use calloc instead of malloc
  3. If I use the void* is there an option to cast it to 32 bytes chunks?
+2  A: 

Your code is doing the right thing: you're working out how many bytes to skip before the aligned block and recording the number in the byte before the block begins. You've got a couple of basic problems:

In C you have either a do { ... } while(cond) loop or a while(cond) { ... } loop, but you've confused the two. Your do while syntax isn't legal, looks like you just want a while loop.

You can't do pointer arithmetic on a void* pointer because void has no size. Compute your new address either as a long: ((long)memblk+offset) or as a pointer to a type that is a single byte in size (like a char). At the moment the addition is on a void* type giving your other compile error.

Guessing what compile errors you are seeing from the code is rather tricky - in future it would be easier if you post the errors that you see as well.

Amoss
I think the OP wants a `do .. while`. `size` is initialized to zero at the top, so the loop won't execute at all if it is just a `while`.
bstpierre
please don't cast a pointer to `long`, `long` and pointers are not guaranteed to have the same width. Then also don't use signed arithmetic on pointer values if you don't need to. `uintptr_t` is probably the right thing (99% of the cases, I'd guess), or if you insist to have a signed type use `intptr_t`.
Jens Gustedt
A: 

Your do-while syntax is wrong. Should be:

do
{
   /* stuff to do */
} while(xxx);

Regarding calloc, it takes (1) the number of "things" you want to allocate, and (2) the size of each thing. It returns a zeroed block of memory with space to hold that number of things.

I don't understand the bit about casting void* to 32 bit chunks.

bstpierre
A: 

My fault SoRRy :-|

Only the returning adresses should be divisble by 32 i.e. 100B -> 64...164 The ALIGNMENT should be set to 32 at the header file and here is a working code:

#include "aligned_malloc.h"

#undef  DEBUG
#define DEBUG 1

int main(void)
{
  size_t size = 0;
  void *res = NULL;

  printf("\nPlease enter size: ");
  scanf("%d", &size);

  while (size > 0) {

    res = aligned_malloc(size);

#ifdef     DEBUG
    printf("%s[%d]: res = 0x%x\n", __FUNCTION__, __LINE__, res);
#endif  /* DEBUG */

    if (res != NULL)
      aligned_free(res);

    printf("\nPlease enter size again (enter 0 to quit): ");
    scanf("%d", &size);
  }

  return 0;
}

void *aligned_malloc(size_t size)
{
  int i = 0;
  long *res = malloc(size + ALIGNMENT);
  unsigned char offset = ALIGNMENT - ((long)res % ALIGNMENT);

  if (res == NULL)
    return NULL;
  /* O/W: */  
#ifdef     DEBUG
  printf("%s[%d]: res = 0x%x\n", __FUNCTION__, __LINE__, res);
#endif  /* DEBUG */
  for (i = offset; i < size + ALIGNMENT; i++) {
      printf("%02d: %08d\n", i, res+i);
      res[i] = 0;
  }

  *(res + offset - 1) = offset;

  return (void*)(res + offset + 1);
}

void aligned_free(void *aligned_p)
{
  unsigned char offset = (unsigned char)(*((unsigned char *)aligned_p-1));
#ifdef     DEBUG
  printf("%s[%d]: offset = %d\n", __FUNCTION__, __LINE__, offset);
  printf("%s[%d]: aligned_p-1 = 0x%x\n", __FUNCTION__, __LINE__, (unsigned char *)aligned_p-1);
  printf("%s[%d]: aligned_p-offset = 0x%x\n", __FUNCTION__, __LINE__, aligned_p-offset);
#endif  /* DEBUG */
  free(aligned_p-offset);
}

PS I don't really know if it is possible to get 32B chunks... THNX

Roey