Pointers and Dynamic Memory

The malloc() function in <stdlib.h> allocates the requested number of bytes from the heap for the application to use.  malloc() returns a void pointer that should be cast to the data type of the pointer. Casting the memory is important because in order for pointer arithmetic to work, the compiler must know the size of the object to which the pointer is pointing. We also use sizeof() to ensure the portability of the code. sizeof() returns the size in bytes of the variable type we wish to allocate memory for.

The free() function returns a previously allocated block of memory to the heap.

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

char *strCpy(const char * str) {
	char *rStr = NULL;
	
	if (str == NULL) {
		return NULL;
	}

	int strLength = strlen(str);

	//add one for the terminating character
	rStr = (char *)malloc(sizeof(char) * strLength + 1);

	if (rStr == NULL) {
		printf("Error allocating memory.\n");
		return NULL;
	}

	//add terminating character for string
	*(rStr + strLength) = '\0';

	while (strLength-- > 0) {
		*(rStr + strLength) = *(str + strLength);
	}

	return rStr;
}

//substring of a larger substring copied onto head and returned
char *substr(const char *theString, int start, int length) {
	char *rStr;
	int count = 0;
	int strLen = strlen(theString);

	//check for bad start position
	if (start < 1) {
		printf("String positions start from 1.\n");
		return NULL;
	}

	if (length < 1) {
		printf("Length must be at least one character long.\n");
	}

	rStr = (char *)malloc(sizeof(char) * (length + 1));

	if (rStr == NULL) {
		printf("Could not allocate the memory.\n");
		return NULL;
	}

	//c strings start at 0
	//so subtract one
	start--;
	
	*(rStr + length) = '\0';

	while (count < length) {
		*(rStr + count) = *(theString + start + count);
		count++;
	}

	return rStr;

}

int main(void) {

	char *newString = strCpy("Nilbog is Goblin Spelled Backwards!");

	printf("%s\n", newString);

	char *newSubStr = substr(newString, 1, 6);

	printf("%s\n", newSubStr);

	//free up the memory when done
	free(newString);
	newString = NULL;

	return 0;
}

It is considered good practice to initialize pointers to NULL and after calling free(). It is also important to verify that the value returned from malloc() is a valid pointer.


const int buffer_max = 256;

double getInput(char *inputBuffer, int bufferSize) {

	int i = 0;

	fgets(inputBuffer, bufferSize, stdin);

	//check for alpha characters
	for (; *(inputBuffer + i) != '\0'; i++) {
		if (iswalpha(*(inputBuffer + i))) {
			return -1;
		}
	}

	return atof(inputBuffer);

}

double * resizeDArray(double **array, int newMax) {
	return (double *)realloc(*array, sizeof(double) * newMax);
}

void printScores(const double *array, int count) {
	for (int i = 0; i < count; i++) {
		printf("%f\t", *(array + i));
		if (count % 5 == 0) {
			printf("\n");
		}
	}
}

double getHighScore(const double *array, int count) {
	double highScore = 0;
	for (int i = 0; i < count; i++) { 		if (*(array + i) > highScore) {
			highScore = *(array + i);
		}
	}
	return highScore;
}

double getLowScore(const double*array, int count) {
	double lowScore = 125;
	for (int i = 0; i < count; i++) {
		if (*(array + y) < lowScore) { 			
                    lowScore = *(array + i); 		
                   } 	
        }   
	
    return lowScore; 

} 

int main() { 	
   char inputBuffer[buffer_max]; 	
   int count = 0; 	
   int max = 5; 	
   double *ptrScores = NULL; 	
   double entry = 0; 	
   double high = 0; 	
   double low = 100; ] 	
   int i = 0, j = 0; 	
   //allocate space for 10 scores 	
   ptrScores = (double *)malloc(sizeof(double) * max); 	
   if (ptrScores == NULL) { 		
       printf("Could not allocate memory.\n"); 		
       exit(0); 	
   } 	
   printf("Please enter the test scores. Once the scores are entered, the program will sort the scores "); 	printf("and calculate the high and low scores.\n\n"); 	while (entry >= 0) {
		
   printf("Enter a score greater than or equal to 0, or a negative number to stop: ");
		
   entry = getInput(inputBuffer, buffer_max);
		
          if (entry >= 0) {
			if (count == (max - 1)) {
				//reallocate memory if there is not enough 
				//increase max size
				max += 5;
				ptrScores = resizeDArray(&ptrScores, max);
			}
			*(ptrScores + count) = entry;
			count++;
		}
	}

	printf("Scores entered: \n");
	printScores(ptrScores, count);

	high = getHighScore(ptrScores, count);
	low = getLowScore(ptrScores, count);

	printf("The high score is %f\n", high);
	printf("The low score is %f\n", low);

	free(ptrScores);

	return 0;
}

The realloc() function takes a previously malloc-ed, realloc-ed, etc. pointer that we want to modify the space it points to in memory. The realloc() function will increase or decrease the size of that space. If realloc() returns NULL, then it failed to allocate the space for some reason; thankfully, the previously allocated space is still there.

 

 

Pointers and Dynamic Linked Lists in C

One of the more awe-inspiring features of C is its use of pointers.

Pointers enable us to create complex and dynamic data structures like linked lists and binary trees. A dynamic data structure is one that can grow or shrink as needed.

Structures can contain pointers, even a pointer to another instance of the same structure.

The malloc() function allocates storage for a variable and then returns a pointer to that storage. Data objects created by malloc() can only be referenced, never named; this means we have to deal with malloc-ed memory via pointers.

#include "stdafx.h"
#include <stdlib.h>

struct dataStruct {
 int iData;
 double dData;
 struct dataStruct *structPtrNext;
};

//use the typedef to create an alias for
//a pointer to the dataStruct structure
typedef struct dataStruct* node;

int main()
{
 node currentNode;
 node startNode = (node)malloc(sizeof(dataStruct));

 startNode->iData = 73;
 startNode->dData = 3.14;
 
 startNode->structPtrNext = (node)malloc(sizeof(dataStruct));
 currentNode = startNode->structPtrNext;

 currentNode->iData = 42;
 currentNode->dData = 19.99;

 currentNode->structPtrNext = (node)malloc(sizeof(dataStruct));

 currentNode = currentNode->structPtrNext;
 currentNode->iData = 404;
 currentNode->dData = .5772;
 currentNode->structPtrNext = NULL;


 currentNode = startNode;
 while (currentNode != NULL) {
  printf("%d \t %f\n", currentNode->iData, currentNode->dData);
  currentNode = currentNode->structPtrNext;
 }


 return 0;
}

The malloc() function takes a single argument, the number of bytes to allocate. If malloc() cannot allocate the requested memory, it returns a null pointer. We can use malloc() to allocate space on an as-needed business. We use the sizeof() operator to determine the size of the structure in bytes; this is easier and less error-prone than using a hard number to allocate the bytes.

The malloc() function gets memory from the heap. To free that memory after we are finished utilizing it, we should call the clearly named free() function. The free() function takes a single argument, the pointer to the block of memory to be freed.

struct structTypeA{
 char chA;
 int iB;
};

struct structTypeB {
 double dA;
 double dB;
};

int main()
{
 printf("Sizeof structTypeA %d\n", sizeof(structTypeA));
 printf("Sizeof structTypeB %d\n", sizeof(structTypeB));

 struct structTypeA *aPtr = NULL;
 struct structTypeB *bPtr = NULL;

 //lets malloc the memory
 aPtr = (structTypeA *)malloc(sizeof(structTypeA));
 if (aPtr != NULL) {
  printf("Memory for the type A structure allocated!\n");
 }

 bPtr = (structTypeB *)malloc(sizeof(structTypeB));

 if (bPtr != NULL) {
  printf("Memory for the type B structure allocated!\n");
 }

 //lets free the memory, return it to the heap
 free(aPtr);
 aPtr = NULL;
 free(bPtr);
 bPtr = NULL;

 return 0;
}

While we do not have to set the pointer to NULL after calling free(), it is generally considered a best practice, as doing so prevents us from trying to use free memory.

Note that the structure pointer operator, ->, provides a shorthand way to access the data field of a structure being pointed to by a pointer.

A linked list is a chain of nodes in which each node points to the next one in the chain. A linked-list data structure is like an array we can grow as needed.

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

const int string_length = 256;

struct linkedList {
 char string[string_length];
 struct linkedList *nextPtr;
};

typedef struct linkedList *list;


int main()
{
 list firstNode = (list)malloc(sizeof(linkedList));
 list nextNode = NULL;

 //set firstNode to point to NULL
 firstNode->nextPtr = NULL;
 strcpy_s(firstNode->string, string_length, "Do you have stairs in your house?");
 

 //create new node for the list
 nextNode = (list)malloc(sizeof(linkedList));

 strcpy_s(nextNode->string, string_length, "Nice boat!");
 //have the new node point to the first node
 nextNode->nextPtr = firstNode;
 //set the first or "top" node to be the new node
 firstNode = nextNode;
 //assign the new node new memory
 nextNode = (list)malloc(sizeof(linkedList));

 strcpy_s(nextNode->string, string_length, "Shaka, when the walls fell.");
 //set the new node to point to the top node
 nextNode->nextPtr = firstNode;
 //set the first node to the node
 firstNode = nextNode;

 //let's do it one more time 

 nextNode = (list)malloc(sizeof(linkedList));

 strcpy_s(nextNode->string, string_length, "For relaxing times, make it Suntory time.");
 nextNode->nextPtr = firstNode;

 firstNode = nextNode;

 while (firstNode != NULL) {
  printf("%s\n", firstNode->string);
  firstNode = firstNode->nextPtr;
 }

 return 0;
}

Of course, it’s easier if we offload some of this into some functions. One of the blessings (some say it is a curse) of dynamically allocated memory is that we are free from worrying about scope.

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


const int string_length = 256;

struct linkNode {
 //unicode strings? why not!
 wchar_t string[string_length];
 struct linkNode *nxtPtr;
};

struct linkNode * initializeList(void) {
 struct linkNode *firstNode = (struct linkNode *)malloc(sizeof(linkNode));
 firstNode->nxtPtr = NULL;
 return firstNode;
}

//need to have a pointer to the pointer
//now we see the point of typedefs!
//we have to have a pointer to a pointer
//in order for the changes to persist
void addNode(struct linkNode **lPtrFirst) {
 struct linkNode *newNode = (struct linkNode *)malloc(sizeof(linkNode));
 if (newNode == NULL) {
 printf("Error allocating memory.\n");
 exit(EXIT_FAILURE);
 }
 newNode->nxtPtr = *lPtrFirst;
 *lPtrFirst = newNode;
}

int main()
{
 wchar_t answer[2];

 struct linkNode *lPtrFirst = initializeList();

 while (true) {
 printf("Please enter the text to store:\t");
 fgetws(lPtrFirst->string, string_length, stdin);

 printf("Would you like to enter another string? (y/n) \t");
 wscanf_s(L"%s", answer, 2);
 //clear buffer
 while (getwchar() != L'\n') {}
   if (answer[0] == L'n' || answer[0] == L'N') {
   break;
 }
  addNode(&lPtrFirst);
 }

 while (lPtrFirst != NULL) {
   wprintf(L"%s", lPtrFirst->string);
   lPtrFirst = lPtrFirst->nxtPtr;
 }

 return 0;
}

Pointers and Dynamic Memory

The malloc() function allocates a certain number of bytes of heap storage for our use. We specify the size of the memory block to allocate in bytes using a value of type size_t, which is an alias of an unsigned integer type. The function returns a pointer to the allocated memory block.

#include "stdafx.h"
#include <stdlib.h>

int main()
{
 size_t NumBytes = 256;
 void *ptrMemBlock;

 ptrMemBlock = malloc(NumBytes);

 if (ptrMemBlock == NULL) {
 printf("Failed to allocated memory.\n");
 exit(EXIT_FAILURE);
 }
 else {
 printf("Allocated memory.\n");
 }

 free(ptrMemBlock);

 return 0;
}

Note that the free() function returns a previously allocated block of memory to the free list.

To reiterate, size_t is a typedef representing the number of bytes to allocate.

The malloc() function returns a null pointer if it fails.

When allocating a block of memory of a particular type, we can use the sizeof() operator to calculate the number of bytes per unit to allocate. The use of sizeof() is important for maintaining portability.

#include "stdafx.h"
#include <stdlib.h>

int main()
{
 size_t byteSize = 512;
 //wchar_t technically isn't standard (?)
 //but we don't follow *their* rules here
 wchar_t *wszStr;

 wszStr = (wchar_t*)malloc(sizeof(wchar_t) * byteSize);

 if (wszStr == NULL) {
 printf("Failed to allocate buffer. Nuts!\n");
 exit(EXIT_FAILURE);
 }
 else {
 //copy the unicode string 
 //wcspy_s takes three params
 //the destination, the max number of wide 
 //chars to copy, and the source
 wcscpy_s(wszStr, byteSize, L"It can be said that the history of science is a history of the expansion of the human body's functionality, in other words, the history of humanity's cyberization.");
 }

 printf("%ls.\n", wszStr);

 free(wszStr);

 return 0;
}

Technically, it’s a good idea to initialize pointers to NULL at declaration and after free. With small programs such as these examples, it may seem extraneous, but its better to get in the habit of doing it always, even when unnecessary, then to forget even once when it is necessary.

Setting unused pointers to NULL is basically all-around good defensive programming, as it protects us from dangling pointer bugs, which can be difficult to track down. Always remember that in C and C++ pointers are inherently unsafe.

 
#include "stdafx.h"
#include <stdio.h>

int main()
{
	int i;
	int *iPtrBlock = NULL;
	
	iPtrBlock = (int *)malloc(sizeof(int) * 4);

	if (iPtrBlock == NULL) {
		printf("Error allocating memory.\n");
		exit(EXIT_FAILURE);
	}

	*iPtrBlock = 42;
	*(iPtrBlock + 1) = 73;
	*(iPtrBlock + 2) = 1138;
	*(iPtrBlock + 3) = 404;

	for (i = 0; i < 4; i++) {
		printf("%d\n", *(iPtrBlock + i));
	}

	//verify we are not passing free()
	//a NULL pointer
	if (iPtrBlock != NULL) {
		free(iPtrBlock);
	}
	
	iPtrBlock = NULL;
	
    return 0;
}


The realloc() function will change the size of the space allocated on the heap. If realloc() returns a NULL, it was unable to allocate any more free space on the heap; however, this is an unlikely event given memory sizes and the amount of data we happen to be working with. The realloc() function returns a pointer, as it may have had to move the memory block in order to fulfill the request to increase the block’s size.

#include <stdlib.h>
#include <Windows.h>

int main()
{
 double dNum = 0;
 const size_t szBuffer_Size = 256;
 const size_t numDigits = 16;
 double *dStorage = (double*)malloc(sizeof(double));
 char szBuffer[szBuffer_Size];
 //get handle for stdin
 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
 DWORD dwBytesRead;
 int iLocation = 0;
 

 while (true) {
 printf("Please enter a number: ");
 ReadFile(hStdin, szBuffer, szBuffer_Size, &dwBytesRead, NULL);
 if (dwBytesRead > numDigits) {
 szBuffer[numDigits] = '\0';
 }
 else {
 szBuffer[dwBytesRead] = '\0';
 }
 //convert string to double
 dNum = atof(szBuffer);

 printf("Entering %f into database.\n", dNum);
 *(dStorage + iLocation) = dNum;
 
 printf("Continue entering numbers? (y/n) ");
 ReadFile(hStdin, szBuffer, szBuffer_Size, &dwBytesRead, NULL);
 *(szBuffer + 1) = '\0';
 if (*szBuffer == 'n' || *szBuffer == 'N') {
 printf("Thank you.\n");
 break;
 }

 iLocation++;

 //allocate more memory
 dStorage = (double*)realloc(dStorage, sizeof(double) * (iLocation + 1));
 } //end while loop

 printf("Numbers entered: \n");
 while (iLocation >= 0) {
 printf("%f \t", *(dStorage + iLocation));
 iLocation--;
 }

 return 0;
}

Allocating and Freeing Dynamic Variables in C

We create a pointer variable to an integer with the declaration int *p; Having declared a variable p as a pointer to a specific type, it is possible to dynamically create an object of that type and assign its address to p.

We do this by calling the standard library function malloc(), which dynamically allocates a portion of memory of a specified size and returns  a pointer to it.

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

int main(void){

    int *i, *j;

    int x;

    i = (int *) malloc(sizeof(int));

    *i = 1138;

    j = i;

    printf("%d %d\n", *i, *j);

    x = 73;

    *i = x;

    printf("%d %d\n", *i, *j);

    *i = 5;

    printf("%d %d\n", *i, *j);

    return 0;

}

The sizeof operator returns the size, in bytes, of its operand.  We can use sizeof in conjunction with malloc() to get an object of the proper size.

The free() function is used to return allocated storage. Calling free() on a pointer makes the memory pointed to by the pointer available for reuse.  While most operating systems “clean up” memory after a program exits, it’s still really a good idea to explicitly clean up any dynamically allocated memory ourselves.

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

int main(void){

    int *p = (int *)malloc(sizeof(int));
    int *q = (int *)malloc(sizeof(int));
    double *d = (double *)malloc(sizeof(double));
    double *e = (double *)malloc(sizeof(double));

    *p = 404;
    *q = 711;
    free(p);    
    p = q;
    printf("%d %d\n", *p, *q);
    
    *d = 0.57721;
    *e = 1.12358;

    printf("%f %f\n", *d, *e);

    free(e);
    e = d;
    *d += 7.11;

    printf("%f %f\n", *d, *e);

    //clean up time
    free(d);
    free(q);
        
    return 0;

}

As we have seen in these past two programs, if two pointers point at the same variable, they are functionally identical. Thus, an assignment to one changes the value of the other.

Next, let’s take a look at creating a linked list using dynamic variables. A linked list consists of a set of nodes, each of which has two fields: an information field and a pointer to the next node in the list. In addition, we have an external pointer that points to the first node in the list.

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

struct node * getNode();

struct node{
    int data;
    struct node *next;
};

int main(void){

    struct node *begin, *temp;    
    struct node *nodePtr;

    temp = getNode();
    temp->data = 42;
    
    begin = temp;
    nodePtr = temp;
    
    nodePtr->next = getNode();
    temp = nodePtr->next;

    temp->data = 73;
    nodePtr = temp;
    nodePtr->next = getNode();

    temp = nodePtr->next;
    temp->data = 1999;
    temp->next = NULL;

    nodePtr = begin;

    while(1){
        printf("%d\n", nodePtr->data);
        if(nodePtr->next==NULL){
            break;
        } else {
            nodePtr = nodePtr->next;
        }
    }
    
    return 0;

}

struct node * getNode(){
    struct node *p;
    p = (struct node *)malloc(sizeof(struct node));
    return p;
}

When looking at the above code, we should ask ourselves how we would go about returning all of the nodes’ memory to the heap.

Note that the getnode() function could as well be implemented via a macro.

Next, let’s look at implementing a list as a queue. A queue follows the first in, first out principle – the first item to be inserted into a queue, will also be the first to be taken out. To do this, we will create a second structure, known as a queue. This structure will have two fields; the first field will be a node pointer to the first node in the list, and the second pointer will be a pointer to the last node in the list.

Our function for getting a queue will initialize both of these fields to NULL. We will then implement two functions, pop() and push(). The pop() function takes a node out out of the queue, frees it in memory, and then returns the value it was storing. The push() function creates a new node, assigns its data field a value, and then assigns it to the end of the queue.

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

struct node *getNode();
struct queue * getQueue();
int empty(struct queue *q);
void push(struct queue *q, int x);
int pop(struct queue *q);

struct node{
    int data;
    struct node *next;
};

struct queue{
    struct node *first;
    struct node *last;
};

int main(void){
    struct queue *q = getQueue();
    printf("queue allocated.");
    if(empty(q)){
        printf("queue is empty.\n");
    }

    push(q, 2001);
    push(q, 2600);
    push(q, 80);
    push(q, 1970);
    push(q, 1701);

    while(empty(q)==0){
        printf("%d\n", pop(q));
    }


    return 0;    
}




struct node * getNode(){
    struct node *p;
    p = (struct node *)malloc(sizeof(struct node));
    return p;
}

struct queue * getQueue(){
    struct queue *q;
    q = (struct  queue*)malloc(sizeof(struct queue));
    q->first=NULL;
    q->last=NULL;
    return q;
}    

int empty(struct queue *q){
    if(q->first==NULL){
        return 1;
    } else {
        return 0;
    }
}

void push(struct queue *q, int x){
    struct node *n = getNode();
    n->data = x;
    n->next = NULL;
    if(q->last!=NULL){
        (q->last)->next = n;    
    } else {
        q->first = n;
    }
    q->last = n;
}

int pop(struct queue *q){
    int x;
    struct node *n = q->first;
    q->first = n->next;
    if(q->first==NULL){
        q->last=NULL;
    }
    x = n->data;
    free(n);
    return x;
}

One of the nice things about working with higher level languages such as C# is that data structures such as linked lists are already implemented for us in the language.

To learn more about C, take a look at my book at http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

 

 

 

 

 

Allocating Memory Storage at Runtime in C

The C library has functions for allocating memory storage space at runtime via a process called dynamic memory allocation. The advantage of dynamic memory allocation over static memory allocation is that we are not required to know how how much memory the program will need before executing the program. All of Cs dynamic memory allocation functions are stored in stdlib.h.

There are four dynamic memory allocation functions that we should know: calloc(), malloc(), realloc(), and free(). The two core functions are malloc() and free(). Each time malloc() is called, a section of free memory is allocated from the heap. Each time free() is called, memory is returned to the system’s heap.

Since we haven’t looked at it previously, first let’s work with calloc(). The calloc() function takes two arguments, whereas the malloc() function takes only one. The first argument is the number of items to allocate memory for, and the second argument is the size of each item in memory. The calloc() function returns a pointer to the first byte of the allocated memory. If there is not enough memory, a null pointer is returned.

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

double *getMem(int numElements);

int main(void){
    
    int i = 0;

    double *ptrToDoubles = getMem(100);
    
    double *ptrToStart = ptrToDoubles;
    
    while(i++ < 100){
        *(ptrToDoubles++) = i * .1587;
    }

    printf("double Array begins at location %p\n", ptrToStart);
    printf("and ends at location %p\n", ptrToDoubles);    

    ptrToDoubles = ptrToStart;

    //print out first item in 
    //dynamic double array
    printf("first element is %f\n",*ptrToDoubles);

    //print out last item in 
    //dynamic doubles array
    printf("last element is %f\n", *(ptrToDoubles+99));

    //free the memory!
    free(ptrToDoubles);
}

double *getMem(int numElements){

    double *ptr;
    
    ptr = calloc(numElements, sizeof(double));

    if(!ptr){
        printf("Allocation error.\n");
        exit(1);
    }

    return ptr;

}

As we have seen above, the free() function returns the memory pointed to by its argument to the heap.

Rather than allocating a group of bytes as malloc() does, calloc() allocates a group of data elements of a set size.

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


int main(void){
    
    //number of elements to create
    unsigned n;
    //index num
    int i;

    int value;    

    int *p;

    printf("How many numbers of type int do you want to allocate?\n");

    scanf(" %u", &n);

    p = calloc(n, sizeof(int));

    if(p!=NULL){
        printf("Memory allocation successful!\n");
    } else {
        printf("Memory allocaion failed!\n");
        return 1;
    }

    while(1){
        printf("What element would you like to assign a value to?");
        printf("(Enter negative number to finish assigning values)\n");

        scanf(" %d", &i);
        if(i < 0){
            break;
        }

        //check if index is within range
        if(i >= n){
            printf("Index out of range.\n");
            continue;
        }

        printf("What value would you like to assign to it?\n");
        scanf(" %d", &value);

        *(p+i) = value;

    }

    //print out values
    i = 0;
    printf("The dynamic int array contains: \n");
    while(i < n){
        printf("%d\n", *(p+i));
        i++;    
    }

    free(p);

    return 0;

}

Note that unlike malloc(), the calloc() function also initializes the stored memory to all zeros, which means that calloc() is slightly slower than malloc().

The malloc() function returns a pointer to the first byte in memory of the size specified as its argument. If there is insufficient memory, the malloc() function will return a null pointer. We should verify that the return value is not null before attempting to use it.

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

struct name{
    char firstName[50];
    char lastName[50];    
};

//returns pointer to name struct
//exits on failure to allocate
struct name *getNameStruct(void){
    struct name *ptr;
    
    if((ptr = malloc(sizeof(struct name)))==NULL){
        printf("Allocation Error.\n");
        exit(1);
    }

    return ptr;

};

int main(void){

    struct name *myName = getNameStruct();
    
    strcpy(myName->firstName, "Al");
    strcpy(myName->lastName, "Jensen");

    printf("First Name %s\n", myName->firstName);
    printf("Last Name %s\n", myName->lastName);

    free(myName);

    return 0;

}

The realloc() function changes the size of a block of memory that was previously allocated by malloc() or calloc(). The first argument is a pointer to the original block of memory. The second argument is the size, in bytes, of the new block.

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


int main(void){
    
    char *ptr1;
    char *ptr2;
    char *ptr3;

    ptr1 = malloc(18 * sizeof(char));

    if(!ptr1){
        printf("Allocation Error.\n");
        return 1;
    }

    strcpy(ptr1, "This is 17 chars.");

    printf("%s\n", ptr1);

    ptr2 = malloc(22 * sizeof(char));

    if(!ptr2){
        printf("Allocation Error.\n");
        return 1;
    }

    strcpy(ptr2, "But this is 21 chars.");    

    ptr3 = realloc(ptr1, 40);
    
    strcat(ptr3, ptr2);

    printf("%s\n", ptr3);    

    //free memory
    //note that ptr3 is reallocated
    //storage of ptr1
    free(ptr2);
    free(ptr3);

    return 0;

}

if you can, please take the time to visit my Amazon.com author page at  http://www.amazon.com/Al-Jensen/e/B008MN382O