Thread: Trying to understand malloc, calloc

  1. #1
    Registered User
    Join Date
    Jul 2002
    Posts
    33

    Trying to understand malloc, calloc

    I am learning to use malloc & calloc.
    I am using strlen with calloc to store the string in memory.
    First thing is that I did not expect is that malloc is reserving 32 bytes for the string instead of strlen+1 bytes.

    Secondly I am getting an exclamation point and some extraneous characters in memory that I have no idea how it got there. I thought it was just random characters so I used calloc instead of malloc but they still appear and always in the same position so it i do not think it is a random thing.

    Appreciate any help to explain this.
    Thanks

    Here is the input
    enter string
    aasdfasdf
    enter string
    t43tq34
    enter string
    45t2q5tyqty
    enter string



    Here is the output x represents null character.

    aasdfasdfxxxxxxxxxxxxxxx!xxxxxxx
    t43tq34xxxxxxxxxxxxxxxxx!xxxxxxx
    45t2q5tyqtyxxxxxxxxxxxxx�xxxxx

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #define OFFSET 0x40
    
    int readline(char *, int);
    
    int main(int argc, char *argv[]) {
    int count, index=0,i=0, stringDone=0;
    char str[50]="", *chrptr, *initPtr=0;
    
    	do {
    		printf("enter string\n");
    	
    		count=readline(str, sizeof(str));
            //printf("%d\n", count);
                    
    		if (count){  //allocate memory
    					
    		    chrptr=(char *)calloc(count,sizeof(char)); //returns pointer to, count includes null char   
    		    //printf("%p\n",chrptr);
    		    
    			if (chrptr == NULL){  //null term is already accounted for
    				printf("malloc error, exiting program\n");
                    exit (0);
                }
                
                if (index == 0) { //save pointer
    				initPtr=chrptr;
    			//printf("%p\n",chrptr);
                }
                
                //strcpy(chrptr,"test");      			  
    			strcpy(chrptr,str);  //strcpy copies the null char to chrptr
    			
    			index++;
    		} 
    	
    	} while (count > 0);
    
    
    chrptr=initPtr;
    
    for(i = 0; i < (32*index) ; i++){
        
        if (*chrptr != '\0'){
            //stringDone=0;
    		printf("%c", *chrptr++);
    	}
    	else {
    		if (*chrptr++ == '\0')  //&& stringDone==0) {
    		  	putchar('x');
    		  	//stringDone=1;
    		
    	}
    }
    	
    return 0;
    }
     
    
    int readline(char* mystr, int n){
    	
    	char ch;
    	int i = 0;
    	
    	while ((ch = getchar()) != '\n') {
    		if (i < n)
    			mystr[i++] = ch;
    	}
    			
    	mystr[i]='\0';   //place null char at end of string
    	return i;
    }
    Last edited by joemccarr; 06-09-2018 at 10:16 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > First thing is that I did not expect is that malloc is reserving 32 bytes for the string instead of strlen+1 bytes.
    malloc can reserve whatever it likes, so long as it's at least the amount you specify.
    It does this for several reasons
    - to perhaps give you scope to call realloc without having to move the memory each time
    - to minimise the effects of fragmentation by having lots of small allocations.
    - to preserve alignment. malloc must always guarantee to return memory with the worst-case alignment on your machine.

    > Secondly I am getting an exclamation point and some extraneous characters in memory that I have no idea how it got there.
    Between each malloc block is usually a malloc control block, telling you such things as where the next free block is, and whether this is an allocated block.

    FWIW, your readline is buggy when the buffer is full.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    A description of what you are trying to achieve would be helpful since your code doesn't make a lot of sense. Are you trying to pack the strings one after the other in memory? calloc offers no such guarantees. It pretty much always allocates more than you ask for and puts extra information in the memory for it's own use, so you can't really scan through it meaningfully the way you are doing (except to peek at malloc's innards).

    If you really need to pack all the strings into one memory area, then you need to either malloc enough space for all the strings, or malloc an initial amount and add to it (realloc) if necessary.

    And you need to allocate 1 extra byte per string for the nul char. And your readline function will write the nul char just out-of-bounds if the string fills the buffer.

    So here's an easy way to store a bunch of strings, but since I don't know what you're up to I don't know if it fits your purpose.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_STRINGS 100
    
    int readline(char *, int);
     
    int main() {
        int len, n = 0;
        char *list[MAX_STRINGS];
        char str[100];
    
        do {
            printf("enter string\n");
            len = readline(str, sizeof(str));
            if (len) {
                if (n  == MAX_STRINGS) {
                    printf("array of strings overflow\n");
                    break;
                }
                char *p = malloc((len + 1) * sizeof *p);
                if (p == NULL) {
                    printf("malloc error, exiting program\n");
                    exit(EXIT_FAILURE);
                }
                strcpy(p, str);
                list[n++] = p;
            } 
        } while (len > 0);
    
        for (int i = 0; i < n; i++)
            printf("%s\n", list[i]);
    
        return 0;
    }
    
    int readline(char* mystr, int n){
        char ch;
        int i = 0;
        while ((ch = getchar()) != '\n' && i < n - 1)
            mystr[i++] = ch;
        mystr[i] = '\0';
        return i;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  4. #4
    Registered User
    Join Date
    Jul 2002
    Posts
    33
    @Salem, thanks for that explaination. That was not explained in the text book I'm going through. At least not yet.

    FWIW, your readline is buggy when the buffer is full.
    I see now how it would overflow now because of the added null character. Is that what you meant ?

    A description of what you are trying to achieve would be helpful since your code doesn't make a lot of sense. Are you trying to pack the strings one after the other in memory?
    @John C. Yes, storing strings efficiently as possible is the goal. I am going thru the C programming book by K.N.King and he shows how using arrays for strings can waste a lot of memory. So he shows how using arrays of pointers to char is more efficient. I was using malloc to get the same efficiency for storing strings without the wasted space. I used calloc to see if those extra characters would disappear since it initializes locations to zero.


    If you really need to pack all the strings into one memory area, then you need to either malloc enough space for all the strings, or malloc an initial amount and add to it (realloc) if necessary.
    Ok, I will try this route.

    Thanks for your code. I am sure I will learn alot from it, like usual.

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Here's one way to do it. Don't look if you're still working on it! :-)

    I've written it so that two '\0' in a row indicates the end of all the strings. But that means it can't hold an empty string (which would just be a '\0' right after the '\0' of the previous string, so it would be two in a row).

    Alternatively, you could perhaps use '\1' to indicate the end of all strings (or any byte that won't occur in any of the strings). Then you could store empty strings. Or you could keep track of the number of strings in the buffer (or possibly the total number of characters), which may be best.

    BTW, getchar() returns an int, so ch in readline should be an int (I didn't catch that first time around).
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int readline(char *, int);
    void *xrealloc(void *p, size_t sz);
    
    int main() {
        char *strbuf = NULL;
        int total_len = 0;
    
        for (;;) {
            char str[100];
            printf("enter string\n");
            int len = readline(str, sizeof(str));
            if (len == 0) break;
            strbuf = xrealloc(strbuf, total_len + len + 1);
            strcpy(strbuf + total_len, str);
            total_len += len + 1;
        }
    
        // add extra '\0'
        strbuf = xrealloc(strbuf, total_len + 1);
        strbuf[total_len] = '\0';
    
        char *p = strbuf;
        do {
            for ( ; *p; p++)
                putchar(*p);
            putchar('\n');
        } while (*++p != '\0');  // check for 2nd '\0' in a row
    
        free(strbuf);
    
        return 0;
    }
    
    int readline(char* mystr, int n){
        int ch;
        int i = 0;
        while ((ch = getchar()) != '\n' && ch != EOF && i < n - 1)
            mystr[i++] = ch;
        mystr[i] = '\0';
        return i;
    }
    
    void *xrealloc(void *p, size_t sz) {
        void *ret = realloc(p, sz);
        if (!ret) {
            if (p) free(p);
            printf("realloc error\n");
            exit(EXIT_FAILURE);
        }
        return ret;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  6. #6
    Registered User
    Join Date
    Jul 2002
    Posts
    33
    Quote Originally Posted by john.c View Post
    Here's one way to do it. Don't look if you're still working on it! :-)
    .....
    I will try not to look but I am not the most disciplined person in the world.

    I am pretty sure that the way I was using malloc etc. is not the way
    to use it (i.e. for each string) as there is way to much waste. So I am re-writing it so that once I get close to the end of the initial 100 byte array then reallocate more storage and go from there keeping track of how many bytes are left before having to reallocate again. But I'm slow and have a day job so it will take a couple of days.

    Thanks for your help.
    Last edited by joemccarr; 06-10-2018 at 10:54 AM. Reason: close the quote tag

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Your way seems a little more sophisticated than the way I did it. I realloc'ed for each string. Your way should be more efficient, although you should realloc when the current string won't fit (not just when you get "close" to the end).


    If you have a specific application, describing the details may lead to more optimization ideas. But it's important to remember that optimization isn't everything, and it's best to write your code as simply as possible and then see if it's too slow (or uses too much memory, etc). If it's too slow, then you should profile it to see where optimization is needed.
    A little inaccuracy saves tons of explanation. - H.H. Munro

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. calloc() vs. malloc()
    By peripatein in forum C Programming
    Replies: 12
    Last Post: 06-22-2013, 10:20 AM
  2. malloc and calloc
    By rrc55 in forum C Programming
    Replies: 15
    Last Post: 09-02-2009, 07:35 PM
  3. malloc, calloc from the FAQ
    By salvadoravi in forum C Programming
    Replies: 10
    Last Post: 01-21-2008, 03:29 AM
  4. calloc vs malloc
    By Jubba in forum C Programming
    Replies: 2
    Last Post: 02-21-2002, 04:54 PM
  5. Calloc vs. Malloc
    By SavesTheDay in forum C Programming
    Replies: 3
    Last Post: 02-18-2002, 03:56 PM

Tags for this Thread