Numerical Arrays

To set a dimension for a numeric array, we imply place a number inside the brackets to the right of the array name. For exampe, alsArray[5] has an array named alsArray that has five possible elements. If we want to declare an int array, we enter int alsArray[10], thereby declaring an array of type int with 10 elements. To declare a double array, we enter double arrayName[7], thereby declaring an array of double values that can hold up to seven elements.

 #include <stdio.h>

int main(void){

    int theArray[10];

    printf("theArray located at memory address %p\n", theArray);
    printf("which is also the address of the first element %p\n", &theArray[0]);

    return 0;
    
}

Note that the name of the array and the memory address of the first element in the array are, in effect, the same.

To access an element in an array, we use the index number of the element. The index number of an element is the offset from the base address of the array, this offset is calculated by the increasing the memory location by the size of the element stored in the array. What this means to us, practically, is that the index value starts at 0 for the first element of the array. Thus, to access the third element in an array, we use the index value 2, and to access the sixth element in the array, we use the index value 5.

#include <stdio.h>

int main(void){

    int intArray[5];

    printf("intArray[0] is located at %p\n", &intArray[0]);
    printf("intArray[2] is located at %p\n", &intArray[2]);
    printf("intArray[0] has the value %d\n\n", intArray[0]);
    printf("the last element in the array is");
    printf("intArray[4] and is located at %p\n", &intArray[4]);
    printf("and has the value of %d\n", intArray[4]);

    return 0;

}

The values stored in each array element are just junk values – they don’t mean anything, they are just the base 10 representation of whatever binary data happened to have been already in the memory location when it was assigned to the array.

It is easy to place our own values into an array. We simply use the assignment operator, =, in conjunction with the index number of the element we wish to which we want to assign a value.

#include <stdio.h>

int main(void){

 int intArray[3];

 intArray[0] = 1729;
 intArray[1] = 404;
 intArray[2] = 6174;

 printf("first element = %d\n", intArray[0]);
 printf("second element = %d\n", intArray[1]);
 printf("third element = %d\n", intArray[2]); 

 return 0;

}

Since index notation is just a simple way to indicate the offset from the array’s base, we can use pointer arithmetic to access elements in the array as well.

#include <stdio.h>

int main(void){

    int array[3];

    int *ptr = array;

    array[0] = 8088;
    *(ptr+1) = 2600;
    array[2] = 90210;

    printf("first element = %d\n", *(ptr));
    printf("second element = %d\n", ptr[1]);
    printf("third element = %d\n", *(ptr+2));

    return 0;

}

Arrays are often passed to functions in a program. When we pass an array, the address of the array’s base s actually copied and passed to the function being called. This means that, in effect, arrays are passed by reference, not by value, so that any changes we make to the array in the called function will persist beyond its own lifetime.

#include <stdio.h>

void calledFunction(int theArray[]);

int main(void){

 int theArray[3];

 theArray[0] = 47;
 theArray[1] = 73;
 theArray[2] = 1776;

 calledFunction(theArray);
 
 return 0; 

}

void calledFunction(int theArray[]){

 printf("parameter array[0] = %d\n", theArray[0]);
 printf("parameter array[1] = %d\n", theArray[1]);
 //don't forget pointer arithmetic also works
 printf("parameter array[2] = %d\n", *(theArray+2));

}

Remember, the whole array is not passed to a function; rather, the starting address of the array is copied into the corresponding parameter. The upside to this is that any changes made to the array are persistent, and we do not have to tie up system resources copying potentially large arrays. The downside is that the called function has no way of knowing the bounds of the array unless it is explicitly informed of the count. We can let a function know what the array’s limits are by passing it an index value indicating the length of the array.

#include <stdio.h>

//don't forget to subscript the
//array parameter
void populateArray(int array[], int length);

int main(void){

    int theArray[8];
    
    //call the array
    populateArray(theArray, 8);

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

    return 0;

}

void populateArray(int array[], int length){
    while(--length > 0){
        array[length] = length + 1;
    }
}

There are times, especially when sorting an array, that two elements in the array must be swapped. The key to swapping the two elements is assigning the value of one of the elements to a temporary variable, so that the value will not be lost during the swap.

#include <stdio.h>


#define SIZE 7

void printArray(int nums[]);
void swapInts(int *a, int *b);

int main(void){

    int nums[SIZE] = {47, 1024, 80, 443, 1701, 1138, 161};

    printArray(nums);    

    swapInts(&nums[2], &nums[5]);

    printArray(nums);

    swapInts(&nums[1], &nums[3]);

    printArray(nums);


    return 0;


}

void swapInts(int *a, int *b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

void printArray(int nums[]){
    for(int i = 0; i < SIZE; i++){
        printf("%d", nums[i]);
        if(i < SIZE - 1){
            printf(", ");
        }
    }
    printf("\n");
}

Finally, let’s write a generalized search function that determines whether or not a specific value is stored in an array. Our function in this example can return either one of two values. The default return value is a negative number; since we cannot have a negative index, a negative return value indicates that the function failed to find the number. If the function does find the desired number in the array, it returns the index of that value.

#include <stdio.h>


void printArray(int array[], int bounds);
int searchArray(int array[], int bounds, int value);

int main(void){

 int arrayLength = 8;
 int searchArrayLength = 5;
 int returnValue;

 int array[] = {64134, 74137, 64111, 64131, 74135, 64131, 20016, 64145};
 int searchVals[] = {73, 64131, 1999, 2001, 74137};

 



 printf("This is the array: ");
 printArray(array, arrayLength);

 for(int i = 0; i < searchArrayLength; i++){
 returnValue = searchArray(array, arrayLength, searchVals[i]);
 if(returnValue < 0){
 printf("Value %d not found.\n", searchVals[i]);
 } else {
 printf("Value %d found at index %d\n", searchVals[i], returnValue);
 }
 }

 

 return 0;

}

int searchArray(int array[], int bounds, int value){
 int i = 0;

 while(i < bounds){
 if(array[i]==value){
 //if match is found
 //return index number
 return i;
 } else {
 i++;
 }
 }

 //if no value match is found
 //return -1
 return -1;
}

void printArray(int array[], int bounds){
 int i = -1;
 int lessBounds = bounds - 1;
 while(++i < lessBounds){
 printf("%d, ", array[i]);
 }
 printf("%d\n", array[lessBounds]);

}

Be sure and take a look at my Amazon author’s page at http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M

 

 

 

 

 

 

 

 

Advertisements

Introduction to Creating Files on Windows using C

NTFS is Window’s go-to filesystem that supports encryption, fault tolerance, compression, and large files. In addition to NTFS, the FAT32 filesystem is often seen on memory sticks.

Unlike in *nix, the pathname separator is the backslash, although the forward slash can be used as well. In general, we should use backslashes just to be safe. Likewise, the full pathname of a file on disk starts with the drive name, such as C: or D:. Finally, filenames are case-insensitive. 

The CreateFile() function opens existing files and creates new ones. The CreateFile() function accepts seven arguments. The second, third, fifth and sixth arguments are of type DWORD; a WORD is an unsigned 16 bit integer, and a DWORD is double that, at 32 bits. Note that the a DWORD is always 32 bits long, even on current 64 bit machines.

The first argument is of type LPCTSTR, which is a const char pointer. LPCTSTR supports unicode (16-bit, rather than 8 bit) character strings as well as ASCII (8 bit) character strings. Pretty much any data type with STR in it represents a string.  Note that when using Visual Studio, we should change our project’s character properties to Not Set. The easiest way to do this is by pressing Alt-F7 and then setting Character Set under Project Defaults to Not Set. 

Essentially, the first argument of type LPCTSTR is a pointer to a null-terminated string representing the pathname, which is normally limited to 260 characters. The fourth argument is of type LPSECURITY_ATTRIBUTES, which is a data structure.

The second argument, which is a DWORD, an unsigned 32 bit integer, accepts either GENERIC_READ or GENERIC_WRITE. To open a file for read/write we can use the bitwise or operator |, as in GENERIC_READ | GENERIC_WRITE.

#include <Windows.h>
#include <stdio.h>

int main(void){

printf("GENERIC READ = 0x%x\n", GENERIC_READ);
printf("GENERIC WRITE = 0x%x\n", GENERIC_WRITE);
printf("READ + WRITE = 0x%x\n", GENERIC_READ | GENERIC_WRITE);

printf("Press any key to continue...");

getchar();

return 0;

}

The third argument is the share mode. If this is set to 0, no other processes, including the one making the call, can access the file. If we specify FILE_SHARE_READ, other processes can access the file for concurrent read access. FILE_SHARE_WRITE allows concurrent writing to the file.

#include <Windows.h>
#include <stdio.h>

int main(void){

//one, basically
printf("FILE_SHARE_READ = 0x%x\n", FILE_SHARE_READ);
//two, basically
printf("FILE_SHARE_WRITE = 0x%x\n", FILE_SHARE_WRITE);

printf("Press any key to continue...");

getchar();

return 0;

}

The SECURITY_ATTRIBUTES structure contains three members, one of which is a pointer to a SECURITY_DESCRIPTOR structure. For now, we will just pass NULL as the argument. 

The fifth argument specifies whether to create, overwrite, open, or truncate the file. If we use CREATE_NEW here, it will create a new file, and more importantly, it will fail if the file already exists. If we specify CREATE_ALWAYS, however, the system will instead overwrite any preexisting files. Likewise, OPEN_EXISTING will fail if the file doesn’t already exist, but OPEN_ALWAYS will go go ahead and create the file if it hasn’t been created already. 

The sixth argument is used to define file attributes and flags for the file. 

 

The CreateFile() function either returns a HANDLE to an open file object, or else an INVALID_HANDLE_VALUE in the event of failure. On current machines, a HANDLE is an unsigned 64 bit value. 

#include <stdio.h>

int main(void){

HANDLE ourHandle;


ourHandle = CreateFile("newfile.txt", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);

if(ourHandle==INVALID_HANDLE_VALUE){
printf("Problem creating file.\n");
printf("Error %x\n", GetLastError());
} else {
printf("File created successfully.\n");
}

printf("Press any key to continue...");

getchar();

return 0;

}

Although Windows closes all open handles on exit, it’s a good idea to close handles no matter what using the CloseHandle() function. Note that the CloseHandle() function returns a Boolean value indicating success or failure.

#include <Windows.h>
#include <stdio.h>

int main(void){

HANDLE theHandle;
LPCTSTR filepath = "another.txt";
bool closed;

theHandle = CreateFile(filepath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if(theHandle!=INVALID_HANDLE_VALUE){
printf("%s created successfully\n", filepath);
}

closed = CloseHandle(theHandle);

if(closed){
printf("HANDLE to %s now closed.\n", filepath);
}

printf("Press any key to continue...");

getchar();

return 0;

}

The win32 CreateFile() function is a bit more complicated than the *nix open() function, which can take as little as two arguments, with the first argument being the pathname and the second argument being the flags for reading or writing the file or directory, and an optional third argument to specify file and directory permissions.

 

 

 

Sorting Strings in C

There are many techniques for encoding and encrypting text. Encoding text means modifying the text’s format so that it can be interpreted by another system; encrypting text means modifying the text so that it can only be interpreted by designated parties.

A transposition cypher is a simple means for encrypting text. In this technique, the text is written as a matrix of characters, then the matrix is transposed and the characters read out.

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <malloc.h>

int main(void){

    char input[100];
    char matrix[10][10];

    int i, spaces, row, column, lineLength, stringLength;

    printf("Please enter a text string to encrypt: \n");
    
    fgets(input, sizeof(input), stdin);

    spaces = 0;
    stringLength = strlen(input);

    for(i = 0; i < stringLength; i++){
        if(input[i]==' '){
            spaces++;
        }
    }

    lineLength = 1 + sqrt(stringLength - spaces);

    //fill matrix with empty spaces
    for(row = 0; row < 10; row++){
        for(column = 0; column < 10; column++){
            matrix[row][column] = ' ';
        }
    }

    row = 0;
    column = 0;
    i = 0;

    while(input[i]!='')
    {
        //leave blank spaces be
        if(input[i]!=' ' && input[i]!='\n'){
            matrix[row][column] = input[i];
            row++;
            //have we reached the end of the line?
            if(row==lineLength){
                row = 0;
                column++;
            }
        }
        i++;
    } //end while

    //print out matrix
    for(row = 0; row < 10; row++){
        for(column = 0; column < 10; column++){
            printf("%c", matrix[row][column]);
        }
        putchar('\n');
    }


    //print out encrypted string
    char *s = (char*)malloc(sizeof(char) * stringLength - spaces);
    
    row = 0;
    column = 0;
    i = 0;
    printf("Encrypted string: %s\n", s);    
    for(row = 0; row < 10; row++){
        for(column = 0; column < 10; column++){
            if(matrix[row][column]!=' ' && matrix[row][column]!='\n'){
                *(s + i) = matrix[row][column];    
                i++;    
            }
        }
    }

    printf("Encrypted string: %s\n", s);
    return 0;

}

Our next program is a simple text formatter. To do this, we must determine how many lines will fit on a single line of text, and then we must figure out how many blank spaces we must include to make sure that the line fills the margins.

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

#define EXPAND_LINE 1
#define NO_EXPAND 0
#define WIDTH 50

void initializeBuffer(char *buff);
void loadWord(char *buffer, char *word, int *spaceremaining);
int getWord(char *text, int index, char *word);
void printLine(char *buffer);

int main(void){

    char *text = "A lot hinges on the fact that, in most circumstances, people are not allowed to hit you with a mallet. They put up all kinds of visible and invisible signs that say 'Do not do this' in the hope that it'll work, but if it doesn't, then they shrug, because there is, really, no mallet at all.";


    char buffer[100];
    char word[100];

    int spaceleft, nextIndex, currIndex;

    spaceleft = WIDTH;

    nextIndex = 0;

    initializeBuffer(buffer);

    while(1){
        //get() function returns int value
        //indicating where to resume search in text
        //side effect is loading next word into word
        //buffer
        nextIndex = getWord(text, currIndex, word);
        if(spaceleft >= strlen(word)){
            //loadword side effects
            //decrements spaceleft
            //loads word into buffer
            loadWord(buffer, word, &spaceleft);
            currIndex = nextIndex;
        } else {
            //print out line
            printLine(buffer);
            //reset buffer
            initializeBuffer(buffer);
            //reset spaceleft
            spaceleft = WIDTH;
        }
        //break out of loop if
        //no more words
        if(strlen(word)==0){
            if(buffer[0]!=''){
                printLine(buffer);
            }
            break;
        }
        
    } // end while loop

    return 0;

}

void initializeBuffer(char *buffer){
    for(int i = 0; i < WIDTH; i++){
        *(buffer+i) = '';
    }
}

int getWord(char *text, int index, char *word){
    int i = 0;
    
    while((text[index]==' ') && (text[index] != '')){
        index++;
    }

    //copy characters into word
    while((text[index]!=' ') && (text[index] != ''))
    {
        *(word+i) = text[index];
        i++;
        index++;
    }
    *(word+i) = '';

    return index;
}

void loadWord(char *buffer, char *word, int *spaceremaining){
    strcat(buffer, word);
    *spaceremaining -= strlen(word);
    if(WIDTH > strlen(buffer)){
        strcat(buffer, " ");
        (*spaceremaining)--;
    }
}


void printLine(char *buffer){

    int index = 0;
    int wordEndIndex  = 0;
    int copyIndex;
    //no need to expand the line
    if(strlen(buffer)==WIDTH){
        printf("%s\n", buffer);
    } else {
        int blanks = WIDTH - strlen(buffer);
    
        while(blanks-- > 0){
            //find end of word
            while(buffer[wordEndIndex]!=' ' & buffer[wordEndIndex]!='\n'){
                wordEndIndex++;
            }    
            for(copyIndex = WIDTH - 1; copyIndex > wordEndIndex; copyIndex--){
                buffer[copyIndex] = buffer[copyIndex - 1];
            }
            buffer[wordEndIndex] = ' ';
            wordEndIndex++;
        }        
        //attach end of line character    
        buffer[WIDTH] = '';
        
        printf("%s\n", buffer);        
    } // end else
}

If you have any interest in learning more about C, take a look at my book at http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

A Simple Stack in C Using an Array

A stack is like a stack of plates – the last plate put on the stack is the first one taken off. This behavior is known as LIFO – last in, first out. Computers in general are stack oriented machines.

The simplest implementation of a stack is as an array. Since the array’s name devolves to a pointer to the first element in the array, we always have a readily available base pointer. It is also possible to implement a stack using linked lists.

The stack can be managed with only two functions: the push() function to write data to the top of the stack, and the pop() function to read data from the top of the stack. As a side effect, the push() function increments the top pointer or array subscript. As a side effect, the pop() function in turn decrements the pointer or array subscript.

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


//add an int to the
//stack
int push(int *stack, int *top);
//return an int
int pop(int *stack, int *top);
//return an int value from stdin
int getInt();

const int stack_size = 10;

int main(void){


    char c, ch;
    int x;

    int stack[stack_size];

    int top = -1;

    while(1){
        printf("Enter command (R)ead, (W)rite, or (Q)uit: ");
        ch = getchar();
        //clear buffer
        while((c = getchar())!='\n');

        switch(ch){
            //assign old value to y
            //newly popped value to x
            case 'r':
            case 'R':
                x = pop(stack, &top);
                printf("Value popped of stack: %d\n", x);
                break;
            case 'w':
            case 'W':
                if((push(stack, &top))<0){
                    printf("Stack is full!\n");
                } else {
                    printf("Value added to stack: %d\n", stack[top]);
                }
                break;
            case 'q':
            case 'Q':
                printf("Exiting...");
                exit(EXIT_SUCCESS);
        }//end switch
            
    }//end while

    return 0;

}

int pop(int *stack, int *top){
    if(*top >= 0){
        int returnInt = *(stack + *top);
//decremement index value to
//top of the stack by one
        (*top)--;
        return returnInt;
    } else {
        return 0;
    }
} //end pop

//note that array name devolves
//to point to base address of the array
int push(int *stack, int *top){
//increment value pointed to by one
    (*top)++;    
//if we are still within the bounds
//of the array, add a value at the next index
    if(*top < stack_size){
        *(stack+(*top)) = getInt();
        return 0;
    } else {
        return -1;
    }
} // end push

int getInt(){
    printf("Please enter the int value: ");
    char input[12];
    fgets(input, sizeof(input), stdin);
    return atoi(input);    
}

The getInt() function reads up to 12 characters from stdin and places it in a buffer called input. The function then converts the char string contained in input to an integer using the atoi() function and returns it to the calling function.

The pop() function accepts two arguments, one being the base address of the int array, which stores the stack values, and the second being a pointer to the integer value that represents the offset needed to retrieve the value at the top of the stack. We pass the second argument as a pointer because we want to manipulate the integer value it points to directly within the function.

The push() function accepts two arguments, one being the base address of the int array, and the second being an integer value passed “by reference” as a pointer. If the value pointed to by the second parameter is less than the bounds of the int array, we can add a value to the top of the stack.  To access the value pointed to by the second parameter, we must use the dereference operator. It is important to remember to use the dereference operator when using the second parameter as an offset to the base address of the int array.

Note that the push() function returns negative one if there is no more room on the stack.

 

 

 

Simple Structures in C

A structure is a collection of one or more variables, where each variable can be a different data type. Structures enable us to group data and work with it as a whole. Our programs are much easier to manage if we can manage several variables via a single structure.

Each structure we define can have an associated name called a structure tag. Structure tags have the same naming rules as variables, but it isn’t the same thing as a variable. A structure tag is actually a new, custom-defined data type.

#include <stdio.h>

struct intStruct{
    int a;
};

int main(void){


    int x;
    struct intStruct y;

    printf("Sizeof int = %ld\n", sizeof(x));
    printf("Sizeof int = %ld\n", sizeof(y));        

    return 0;

}

To define a structure, we use the struct statement. Note that the structure tag is actually optional.

We can then define local structure variables using the appropriate structure tag. The structure tag keeps us from having to redefine the structure members each time we want to use a particular structure.

#include <stdio.h>


struct {
    int a;
    int b;
    double c;
} x, y;

int  main(void){

    printf("Sizeof int = %ld\n", sizeof(int));
    printf("Sizeof char = %ld\n", sizeof(char));
    printf("Sizeof double = %ld\n", sizeof(double));

    printf("\nSizeof x = %ld\n", sizeof(x));
    printf("Sizeof y = %ld\n", sizeof(y));        

    return 0;

}

We can initialize structure members when we define a structure variable, and we can initialize a structure within the body of a program.

To assign a value to a structure member in a program, we use the dot operator. The dot operator is a period placed between the structure variable’s name and its member name. A structure variable name must always precede the dot operator, and a member name must always appear after the dot operator.

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


struct employee{
    int id;
    char firstName[50];
    char lastName[50];
};


int main(void){

    struct employee a;
    
    a.id = 1138;
    strcpy(a.firstName, "Joel");
    strcpy(a.lastName, "Hodgson");

    printf("%d %s, %s\n", a.id, a.lastName, a.firstName);

    return 0;

}

It is possible to define an array of a particular structure type.

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

struct student{
    char firstName[50];
    char lastName[50];
    int age;
    double average;
};

int main(void){

    struct student students[3];

    strcpy(students[0].firstName, "Ponyboy");
    strcpy(students[0].lastName, "Curtis");
    students[0].age = 14;
    students[0].average = 3.4;

    strcpy(students[1].firstName, "Sodapop");
    strcpy(students[1].lastName, "Curtis");
    students[1].age = 16;
    students[1].average = 2.7;     
    
    strcpy(students[2].firstName, "Johnny");
    strcpy(students[2].lastName, "Cade");
    students[2].age = 14;
    students[2].average = 2.5;

    printf("Name: %s, %s\n", students[1].lastName, students[1].firstName);
    printf("Age: %d\n" , students[1].age);
    printf("Avg: %f\n", students[1].average);
    
    return 0;

}

Structure variables are passed to functions by copy, not by reference. If we wish to have changes to a structure persist beyond the lifetime of the called function, we must either return the entire structure to the calling function, or else pass the structure variable by reference.

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

struct point InstantiatePoint(char *name, int x, int y);

struct point{
    char name[20];
    int x;
    int y;
};

int main(void){

    struct point points[3];

    points[0] = InstantiatePoint("ptA", 50, 100);
    points[1] = InstantiatePoint("ptB", 17, 257);
    points[2] = points[1];

    printf("%s (%d, %d)\n", points[2].name, points[2].x, points[2].y);

    return 0;

}


struct point InstantiatePoint(char *name, int x, int y){
    struct point returnPoint;
    
    strcpy(returnPoint.name, name);
    returnPoint.x = x;
    returnPoint.y = y;

    return returnPoint;
}


Note that you can copy one structure variable to another structure variable as long as both structures have the same format.

Interested in learning more about C? Take a look at my book at http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M