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;
}
Advertisements

Data and Memory in C

Computers keep track of memory by using addresses. Computers maintain addresses of bytes.  A byte is 8 bits arranged in order in memory. Each bit represents a position whose value is 2 to the power of n, where n is the numeric value of the bit’s position, starting from 0. By convention, the leftmost bit is called the most significant bit, as this has the largest value (2^7), whereas the rightmost bit is called the least significant bit, as it has the value of 2^0, which is 1.

We use bytes to form memory objects. A memory object, not to be confused with an object that is an instantiation of a class, is a region of memory made up of a contiguous collection of bytes in order to store a value. All objects have addresses, which is the address of the object’s first byte in memory. On microcomputers, this byte is the smallest.

A variable is thus a memory object that has a name, and has an amount of storage determined by its type. Variables are declared, whereby the compiler is told that a variable will be used and what its data type is. A variable can be assigned an initial value when it is declared. The C language has a number of types, such as char, which stores an ASCII character, an int, which stores a whole number, an unsigned int, which stores a positive whole number, and a double, which stores a double-precision floating-point number.

The char type specifies an ASCII character. Any ASCII character is guaranteed to have a positive value. The char keyword sets the type of the memory object and the identifier, which is the variable’s name.

#include    <stdio.h>    
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char cX = 'c';
char cY = 100;

printf("%c \t %c\n", cX, cY);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

The expression ‘c’ is called a character constant. It yields the numeric value that is stored to represent the character. Note that it uses a pair of single quotation marks, not double quotation marks.  Double quotation marks are used to delimit a string literal. A string literal is stored as an array of characters. We can access it either via a char pointer or a char array.

#include    <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char *szStringOne = "El Psy Congroo";
char szStringTwo[] = "Nice Boat!";

printf("%s\n", szStringOne);
printf("%s\n", szStringTwo);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

An equals sign in C, as in most languages, assigns the value of an expression on the right side to the memory object on left side.

Formatting characters, such as newline or tab, are represented via escape sequences. For instance, you can’t put a newline in a string literal by pressing Enter, as that only puts a newline in the source code! The escape sequence for a tab is \t and the escape sequence for a newline is \n.  Single and double quotation marks can also be represented via escape sequences, \’ and \”, respectively.

While the size of an int variable isn’t specified, it is typically 32 bits, which was the word size on x86 machines. Note that an int value is still 32 bits. Long or at least long long values should be 64 bits in length. Pointers are 64 bits as well, at least on x64 machines

#include     <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
int iValue;
int *piValue;
long long llValue;

printf("size of an int = %lu\n", sizeof(iValue));
printf("size of a pointer = %lu\n", sizeof(piValue));
printf("Size of a long long = %lu\n", sizeof(llValue);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- *

Computers keep track of memory by using addresses. Computers maintain addresses of bytes.  A byte is 8 bits arranged in order in memory. Each bit represents a position whose value is 2 to the power of n, where n is the numeric value of the bit’s position, starting from 0. By convention, the leftmost bit is called the most significant bit, as this has the largest value (2^7), whereas the rightmost bit is called the least significant bit, as it has the value of 2^0, which is 1.

We use bytes to form memory objects. A memory object, not to be confused with an object that is an instantiation of a class, is a region of memory made up of a contiguous collection of bytes in order to store a value. All objects have addresses, which is the address of the object’s first byte in memory. On microcomputers, this byte is the smallest.

A variable is thus a memory object that has a name, and has an amount of storage determined by its type. Variables are declared, whereby the compiler is told that a variable will be used and what its data type is. A variable can be assigned an initial value when it is declared. The C language has a number of types, such as char, which stores an ASCII character, an int, which stores a whole number, an unsigned int, which stores a positive whole number, and a double, which stores a double-precision floating-point number.

The char type specifies an ASCII character. Any ASCII character is guaranteed to have a positive value. The char keyword sets the type of the memory object and the identifier, which is the variable’s name.

#include    <stdio.h>    
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char cX = 'c';
char cY = 100;

printf("%c \t %c\n", cX, cY);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

The expression ‘c’ is called a character constant. It yields the numeric value that is stored to represent the character. Note that it uses a pair of single quotation marks, not double quotation marks.  Double quotation marks are used to delimit a string literal. A string literal is stored as an array of characters. We can access it either via a char pointer or a char array.

#include    <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char *szStringOne = "El Psy Congroo";
char szStringTwo[] = "Nice Boat!";

printf("%s\n", szStringOne);
printf("%s\n", szStringTwo);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

An equals sign in C, as in most languages, assigns the value of an expression on the right side to the memory object on left side.

Formatting characters, such as newline or tab, are represented via escape sequences. For instance, you can’t put a newline in a string literal by pressing Enter, as that only puts a newline in the source code! The escape sequence for a tab is \t and the escape sequence for a newline is \n.  Single and double quotation marks can also be represented via escape sequences, \’ and \”, respectively.

While the size of an int variable isn’t specified, it is typically 32 bits, which was the word size on x86 machines. Note that an int value is still 32 bits. Long or at least long long values should be 64 bits in length. Pointers are 64 bits as well, at least on x64 machines

 #include     <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
int iValue;
int *piValue;
long long llValue;

printf("size of an int = %lu\n", sizeof(iValue));
printf("size of a pointer = %lu\n", sizeof(piValue));
printf("Size of a long long = %lu\n", sizeof(llValue);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

Computers keep track of memory by using addresses. Computers maintain addresses of bytes.  A byte is 8 bits arranged in order in memory. Each bit represents a position whose value is 2 to the power of n, where n is the numeric value of the bit’s position, starting from 0. By convention, the leftmost bit is called the most significant bit, as this has the largest value (2^7), whereas the rightmost bit is called the least significant bit, as it has the value of 2^0, which is 1.

We use bytes to form memory objects. A memory object, not to be confused with an object that is an instantiation of a class, is a region of memory made up of a contiguous collection of bytes in order to store a value. All objects have addresses, which is the address of the object’s first byte in memory. On microcomputers, this byte is the smallest.

A variable is thus a memory object that has a name, and has an amount of storage determined by its type. Variables are declared, whereby the compiler is told that a variable will be used and what its data type is. A variable can be assigned an initial value when it is declared. The C language has a number of types, such as char, which stores an ASCII character, an int, which stores a whole number, an unsigned int, which stores a positive whole number, and a double, which stores a double-precision floating-point number.

The char type specifies an ASCII character. Any ASCII character is guaranteed to have a positive value. The char keyword sets the type of the memory object and the identifier, which is the variable’s name.

#include    <stdio.h>    
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char cX = 'c';
char cY = 100;

printf("%c \t %c\n", cX, cY);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

The expression ‘c’ is called a character constant. It yields the numeric value that is stored to represent the character. Note that it uses a pair of single quotation marks, not double quotation marks.  Double quotation marks are used to delimit a string literal. A string literal is stored as an array of characters. We can access it either via a char pointer or a char array.

#include    <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char *szStringOne = "El Psy Congroo";
char szStringTwo[] = "Nice Boat!";

printf("%s\n", szStringOne);
printf("%s\n", szStringTwo);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

An equals sign in C, as in most languages, assigns the value of an expression on the right side to the memory object on left side.

Formatting characters, such as newline or tab, are represented via escape sequences. For instance, you can’t put a newline in a string literal by pressing Enter, as that only puts a newline in the source code! The escape sequence for a tab is \t and the escape sequence for a newline is \n.  Single and double quotation marks can also be represented via escape sequences, \’ and \”, respectively.

While the size of an int variable isn’t specified, it is typically 32 bits, which was the word size on x86 machines. Note that an int value is still 32 bits. Long or at least long long values should be 64 bits in length. Pointers are 64 bits as well, at least on x64 machines

#include     <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
int iValue;
int *piValue;
long long llValue;

printf("size of an int = %lu\n", sizeof(iValue));
printf("size of a pointer = %lu\n", sizeof(piValue));
printf("Size of a long long = %lu\n", sizeof(llValue);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- *

Computers keep track of memory by using addresses. Computers maintain addresses of bytes.  A byte is 8 bits arranged in order in memory. Each bit represents a position whose value is 2 to the power of n, where n is the numeric value of the bit’s position, starting from 0. By convention, the leftmost bit is called the most significant bit, as this has the largest value (2^7), whereas the rightmost bit is called the least significant bit, as it has the value of 2^0, which is 1.

We use bytes to form memory objects. A memory object, not to be confused with an object that is an instantiation of a class, is a region of memory made up of a contiguous collection of bytes in order to store a value. All objects have addresses, which is the address of the object’s first byte in memory. On microcomputers, this byte is the smallest.

A variable is thus a memory object that has a name, and has an amount of storage determined by its type. Variables are declared, whereby the compiler is told that a variable will be used and what its data type is. A variable can be assigned an initial value when it is declared. The C language has a number of types, such as char, which stores an ASCII character, an int, which stores a whole number, an unsigned int, which stores a positive whole number, and a double, which stores a double-precision floating-point number.

The char type specifies an ASCII character. Any ASCII character is guaranteed to have a positive value. The char keyword sets the type of the memory object and the identifier, which is the variable’s name.

#include    <stdio.h>    
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char cX = 'c';
char cY = 100;

printf("%c \t %c\n", cX, cY);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

The expression ‘c’ is called a character constant. It yields the numeric value that is stored to represent the character. Note that it uses a pair of single quotation marks, not double quotation marks.  Double quotation marks are used to delimit a string literal. A string literal is stored as an array of characters. We can access it either via a char pointer or a char array.

#include    <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
char *szStringOne = "El Psy Congroo";
char szStringTwo[] = "Nice Boat!";

printf("%s\n", szStringOne);
printf("%s\n", szStringTwo);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

An equals sign in C, as in most languages, assigns the value of an expression on the right side to the memory object on left side.

Formatting characters, such as newline or tab, are represented via escape sequences. For instance, you can’t put a newline in a string literal by pressing Enter, as that only puts a newline in the source code! The escape sequence for a tab is \t and the escape sequence for a newline is \n.  Single and double quotation marks can also be represented via escape sequences, \’ and \”, respectively.

While the size of an int variable isn’t specified, it is typically 32 bits, which was the word size on x86 machines. Note that an int value is still 32 bits. Long or at least long long values should be 64 bits in length. Pointers are 64 bits as well, at least on x64 machines

 #include     <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
int iValue;
int *piValue;
long long llValue;

printf("size of an int = %lu\n", sizeof(iValue));
printf("size of a pointer = %lu\n", sizeof(piValue));
printf("Size of a long long = %lu\n", sizeof(llValue);

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

As we have seen, the printf() function can handle both fixed and variable parts. The function takes at least one argument, the format string that contains both literal text and conversion specifiers. The values stored in optional arguments sent after the format string literal are inserted in the places indicated by the conversion specifiers. The literal text is printed unchanged.

The %d conversion specifier is used for int values. The %c specifier is used for char values. The %u specifier is used for unsigned values. The %x specifier converts an unsigned integer to hexadecimal notation.

#include    <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
unsigned x = 0;

for(x; x < 100; x++){
printf("%d \t %x \n", x, x);
}

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

As we have seen, the printf() function can handle both fixed and variable parts. The function takes at least one argument, the format string that contains both literal text and conversion specifiers. The values stored in optional arguments sent after the format string literal are inserted in the places indicated by the conversion specifiers. The literal text is printed unchanged.

The %d conversion specifier is used for int values. The %c specifier is used for char values. The %u specifier is used for unsigned values. The %x specifier converts an unsigned integer to hexadecimal notation.

#include    <stdio.h>
#include    <stdlib.h>
/* ------ main function ------- */

int main ( int argc, char *argv[] )
{
unsigned x = 0;

for(x; x < 100; x++){
printf("%d \t %x \n", x, x);
}

return EXIT_SUCCESS;
}

/* ----------  end of main function  ---------- */

Floating point numbers are real numbers; they include the types float, double, and long double. Each of these types varies in the precision with which a particular value is stored and expressed. A long double may or may not be more precise than a double, and float value types are rarely used.

Introduction to Arrays in C

An array is a list of more than one variable having the same name.  Each variable in an array is known as an array element. We differentiate array elements by a subscript, which is  a number inside brackets. All array subscripts begin at zero, not one.

We can control individual elements in an array by their subscripts.

#include <stdio.h>

int main(void){

    int intArray[5];

    intArray[0] = 42;
    intArray[1] = 73;
    intArray[2] = 90210;
    intArray[3] = 64111;
    intArray[4] = 1138;


    printf("intArray[2] = %d\n", intArray[2]);
    printf("intArray[4] = %d\n", intArray[4]);


    return 0;

}

We can define an array as any data type in C. We can have integer arrays, long integer arrays, double arrays, char arrays, and so on. The compiler recognizes that we are defining an array, and not a single non-array variable, when we put brackets after the array’s name.

#include <stdio.h>

int main(void){

    
    char arrayChar[6];
    
    arrayChar[0]='H';
    arrayChar[1]='e';
    arrayChar[2]='l';
    arrayChar[3]='l';
    arrayChar[4]='o';
    arrayChar[5]='!';


    int i = 0;

    while(i<7){
        putchar(arrayChar[i++]);
    }



    return 0;

}


When we define an array, we tell the compiler to reserve a specific number of memory locations for that array by setting how many elements are in the array. Each element in an array uses the same amount of storage as a variable of the same type. C stores all array elements in a contiguous block.

#include <stdio.h>

int main(void){
 
  int n;
  int intArray[5];
 
  double j;
  double dubArray[5];
 
  printf("Size of a single int variable: %lu\n",
     sizeof(n));
 
  printf("Size of the intArray: %lu\n", sizeof(intArray));
 
  printf("Size of a single double variable: %lu\n",
     sizeof(j));
  printf("Size of a the dubArray: %lu\n", sizeof(dubArray));
 
  return 0;
 
}

We need to be sure to keep our subscript values within the range that we set when we declared the array.

We can create a string by initializing a char array with a character string. Note that with a string, we need an extra array element to hold the null zero at the end of the quoted string. A string is really just a char array where the last element is a null zero.

#include <stdio.h>

int main(void){
 
  char state1[15]="Missouri";
  char state2[15]="Nebraska";
 
  printf("%s and %s",
     state1, state2);
 
  char state3[15]={'K', 'a', 'n', 's', 'a', 's', ''};
 
  printf("\nand %s\n", state3);
 
  return 0;
 
}

We should always define an array with the maximum number of desired elements indicated in the subscript, unless we initialize the array at the same time.

#include <stdio.h>

int main(void){
 
  int nums[] = {1,3,5,7,11,13,17};
  long long bigNums[] = {8675309, 6647276};
 
  printf("%lld\n", bigNums[0]);
  printf("%d\n", nums[3]);
 
 
  return 0;
 
}

Our final example is a program to calculate the average of a set of grades given as double float values.

#include <stdio.h>

void printScores(double array[], int size);

int main(void){
 
  char uName[] = "Camden College";
 
  double grades[7] = {97.0, 81.3, 100.0, 89.9, 75.8, 88.5, 93.9};
 
  double averageGrade=0.0;
 
  int i;
 
 
  printScores(grades, 7);
 
  for(i=0; i<7; i++){
    averageGrade+=grades[i];
  }
 
  averageGrade/=7.0;
 
 
  printf("At %s, your average is %.1f\n",
     uName, averageGrade);
 
  return 0;
 
}

void printScores(double array[], int size){
  printf("Here are your grades:\n");
 
  int i;
  for(i=0;i<size;i++){
    printf("%.1f\n", array[i]);
  }
 
}

Note that to pass an array to a function, we need to specify only its name. In the function’s parameter list, we need to state the array type and include brackets after the array name.