Arrays and Strings in C

An array is an indexed list of variables of the same type that are referred to by a shared name. A specific variable in the array is accessed via its index number. In C, all arrays consist of contiguous memory locations, which means that we can also access array elements via pointer arithmetic. The lowest address stores the first array element, and the highest address stores the last element. Suffice to say, arrays and pointers are closely related.

One common type of array is the string, which is a char array terminated by the null character.

As with other variables, arrays must be declared so that the compiler can allocate space for them in memory.

#include <stdio.h>

int main(void){
    
    
    //declare double type array
    double bubble[10];
    
    //declare int type array
    int intArray[50];
    
    bubble[0] = 7.976;
    bubble[1] = 2.352;
    
    printf("bubble[0] = %f\n", bubble[0]);
    printf("bubble[1] = %f\n", bubble[1]);
    
    return 0;
    
}

As we have seen, an element is accessed by indexing the array name, which is done by placing the number of the element’s location in the array within square brackets after the name of the array. Note that in C, all arrays have 0 as the index of their first element.

#include <stdio.h>

int main(void){
    
    int ints[50];
    
    int i;
    
    //assign values to
    //every element in ints array
    for(i = 0; i < 50; i++){
        ints[i]=i+1;
    }
    
    //display contents of array
    for(i=0; i < 50; i++){
        printf("%d\t", ints[i]);
    }
    
    putchar('\n');
    
    return 0;
    
}

Note that C has no bounds checking on arrays.

The amount of memory required to hold an array is directly related to its type and size. For a single-dimension array, the total size in bytes is the length of the array multiplied by the size of the base type of the array.

We can create a pointer to the first element in an array by specifying the array name without any sort of index.

#include <stdio.h>

int main(void){
    
    int i = 0;
    int *ptr;
    int sample[25];
    
    ptr = sample;
    
    sample[0] = 1;
    for(i = 1; i < 25; i++){
        sample[i] = i + sample[i-1];
    }
    
    i = 0;
    
    //use pointer arithmetic
    //to access array elements
    while(i++ < 25){
        printf("%d\n", *ptr++);
    }
    
    return 0;
}

We cannot pass an entire array as an argument to a function. We can, however, pass a pointer to an array by specifying the array’s name without an index. We can declare the array as a function parameter in three different ways: as a pointer, as a  sized array, or as an unsized array.

#include <stdio.h>
#define SIZE 50

//two void functions
//one to assign values
//one to print values
void assignValues(double array[SIZE]);
void printValues(double *arrayPtr);

//one void function to modify values
void modifyValues(double array[]);

int main(void){
    
    double trouble[SIZE];
          
    assignValues(trouble);
    
    printValues(trouble);
    
    printf("\nafter modifying values in array...\n");
                
    modifyValues(trouble);
    
    printValues(trouble);
    
    return 0;
    
}

void assignValues(double array[SIZE]){
    
    int i;
    double var = 0.0;
    
    for(i = 0; i < SIZE; i++){
            var = i / 1000.0;
            array[i] = (i-(SIZE/2)) + var;
        }
}

void printValues(double *arrayPtr){
    int i = 0;
    while(i < SIZE){
        printf("%.8f\n", *(arrayPtr + i));
        i++;
    }
}

void modifyValues(double array[]){
    int i;
    for(i = 0; i < SIZE; i++){
        array[i] = array[i] / (i+1) + i;
    }
}

One dimensional arrays are often used as strings. A string is a null-terminated character array. Note that when declaring a character array that will hold a string, we must declare it to be one character longer than the largest string that it will hold.

#include <stdio.h>


int main(void){
    
    int i;
    char lowerCase[27];
    char upperCase[27];
    
    lowerCase[0] = 'a';
    upperCase[0] = 'A';
    
    for(i = 1; i < 26; i++){
        lowerCase[i] =  lowerCase[0] + i;
        upperCase[i] = upperCase[i-1] + 1;
    }
    
    //assign null terminator
    //to ends of the string
    lowerCase[26] = '';
    upperCase[26] = '';
    
    //print strings using
    // %s conversion specifier
    printf("Lower Case Letters: %s\n", lowerCase);
    printf("Upper Case Letters: %s\n", upperCase);
    
    
    return 0;
}

We can use the fgets() function to acquire a string from standard input. The fgets() function takes three arguments: the char array, the size of the char array, and where to get the input from. Since we will be taking the input from the user, we will specify stdin as the source of input.

#include <stdio.h>

int main(void){
    
    const int buffer = 256;
    
    char string1[buffer];
    char string2[buffer];
    
    printf("Enter a string: ");
    
    fgets(string1, buffer, stdin);
    
    printf("Enter another string: ");
    
    fgets(string2, buffer, stdin);
    
    printf("%s", string1);
    
    printf("%s", string2);

    return 0;
    
}

Interested in learning more?

Take a look at this book on C: http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

Advertisements

NULL and Void Pointers

The indirection operator, represented by an *, returns the value pointed to by a pointer variable; we call this action dereferencing a pointer.

#include <stdio.h>


int main(void){
    
    int number = 47;
    
    int *p = &number;
    
    printf("%d\n", *p);
    
    *p = 73;
    
    //displays 73
    printf("%d\n", number);
    
    return 0;
}

The NULL pointer constant is a pointer that does not point to anything; this means that it does not point to an area of memory. NULL is defined as (void *)0. 

#include <stdio.h>


int main(void){
    
    int *p = NULL;
    int  *p2 = (void *)0;
    //displays (nil)
    printf("%p\n", p);
    
    //displays (nil)
    printf("%p\n", p2);
    
    return 0;
}

Note that NULL should not be used in contexts other than pointers.

A pointer to void can be used to hold references to any data type.The void keyword here is meant to indicate an absence of type. We can think of a void pointer as a sort of general purpose pointer.

#include <stdio.h>


int main(void){
    double dare = 1.61803;
    char letter = 's';
    
    //declare and initialize
    //void pointer
    void *ptr = &dare;
    ptr = &letter;
    
    return 0;
    
}

We cannot directly dereference a void pointer. We must instead cast it to a pointer with a specific type; for instance, int *, double*, char*, etc. Casting, as we know, is a way to tell the machine to treat a value of one type as if it were another type.

#include <stdio.h>


int main(void){
    int i = 73;
    double decker = 3.14159;
    void *ptr = &i;
    
    printf("%d\n", *((int*)ptr));
    
    
    ptr = &decker;
    
    printf("%f\n", *((double*)ptr));
    return 0;
    
}

 

Note that we cannot perform pointer arithmetic on void pointers.

#include <stdio.h>


int main(void){
    
    double trouble = 0.57721;
    double *dPtr = &trouble;
    double *dPtr2;
    
    int number = 8088;
    int *iPtr = &number;
    int *iPtr2;
    
    //don't use ampersand
    void *ptr = dPtr;
    
    dPtr2 = (double *)ptr;
    
    printf("*dPtr2 = %f\n", *dPtr2);
    
    //don't use ampersand
    ptr = iPtr;
    
    iPtr2 = (int*)ptr;
    
    
    printf("*iPtr2 = %d\n", *iPtr2);
    
    return 0;
}

 

Character Input/Output Functions in C

Character input functions read one character at a time from a text stream, while character output functions write one character at a time to a text stream.

Our first example program will read from standard input and then print out the data back to the screen.  The getchar() function reads the next character from stdin and returns its value. The putchar() function writes one character to standard output.

#include <stdio.h>

#define LENGTH 50

int main(void){
    
    
    //return type of getchar()
    //is int not char
    int character;
    int i = 0;
    char string[LENGTH];
    
    while(i<LENGTH-1){
        //EOF can be sent using CTRL-D on
        //Linux systems
        if((character=getchar())!=EOF){
            string[i++]=character;
        } else {
            break;
        }
    }
    
    string[LENGTH-1]='';
    
    i=0;
    //print out text
    while(string[i]!=''){
        putchar(string[i++]);
    }

    return 0;
}

Note that the return type of the getchar() function is an int and not a char; this is because EOF is defined as an integer.

The fputc() function writes the character argument to the specified file stream. The fist argument is the character to be written and the second argument is the file. If the character is written, the fputc() function returns the value of the character. In the event of an error, it returns EOF.

#include <stdio.h>


int main(void){
    

    FILE *filePointer;
    int c;
    
    printf("Input will be copied toa file.\n");
    printf("When finished, enter EOF.\n\n");
    
    
    if(!(filePointer=fopen("testfile.txt", "w")))
    {
        printf("Error opening the file for writing.\n");
        return 1;
    }
    
    while((c = getchar())!=EOF){
        fputc(c, filePointer);
    }
    
    if((fclose(filePointer))==EOF){
        printf("Error closing file.\n");
        return 100;
    }
    return 0;
}

The fclose() function closes the file stream. It takes the pointer to the file stream object as its argument, and returns 0 upon success, and EOF in the event of failure.

The fgetc() function reads the next character from the file stream and converts it to an int value. If it detects an end of file, it returns EOF. Note that an EOF is also returned if any errors happen.

Our next program will copy the contents of one text file to another. 

#include <stdio.h>


int main(void){
    
    int character;
    FILE *copyFromPtr;
    FILE *copyToPtr;
    
    printf("Copying file...\t");
    
    if(!(copyFromPtr = fopen("testfile.txt", "r"))){
        printf("Error opening testfile.txt for reading.\n");
        return 1;
    }
    
    if(!(copyToPtr = fopen("testfile2.txt", "w"))){
        printf("Error opening testfile2.txt for writing.\n");
        return 1;
    }
    
//read one character from one file
//and then copy to another
    while((character=fgetc(copyFromPtr))!=EOF){
        fputc(character, copyToPtr);
    }
    
    if((fclose(copyFromPtr))==EOF){
        printf("Error closing the file we were copying from.\n");
        return 1;
    }
    
    if((fclose(copyToPtr))==EOF){
        printf("Error closing the file we were copying to.\n");
        return 1;
    }
    
    printf("File successfully copied.\n");
    
    return 0;
}

Want to learn more? My book on C programming contains over 200 brand new example programs, exercises, and detailed explications. Take a look at: http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

I also have a book on working from the Linux command line, only .99 cents for a limited time: http://www.amazon.com/Big-Als-Linux-Fedora-CLI-ebook/dp/B00GI25V30/

 

 

Memory in C

C utilizes three types of memory: static memory, automatic memory, and dynamic memory. Static memory we know from static variables. This memory persists from the beginning to the end of the program. Automatic, or local, memory is allocated when the function it is in is called, and persists until the function ends. Dynamic memory is allocated from the heap, and persists until it is specifically released. Dynamic memory is accessed via pointers.

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

//static memory
static int staticMem;

int main(void){
    
    //automatic memory
    int autoMem;
    
    
    //get dynamic memory from 
    //the heap
    int * buffer = (int*)malloc(10);
    
    //release the memory
    free(buffer);
    
    return 0;
}

A pointer holds the memory address of another variable, function, or object. Memory is allocated using one of the memory allocation functions, usually malloc(). The free() function is used to release dynamic memory. Note that the malloc() and free() functions are defined in the stdlib.h header file.

Pointers are one of the best and worst parts of C. Facility with pointers is considered a sort of sine qua non for professional programmers; although, with the growth of languages using managed code it is a less vital subject. The cryptic nature of pointer notation acts as a sort of shibboleth among programmers and in certain companies. In C, however, a deep understanding of pointers really is vital, as pointers and dynamic memory enable us to create data structures.

#include <stdio.h>

int main(void){
    
    int i,j;
    char * strings[] = {"Three pounds of flax", "Photons be free!", "Han shot first", "Access to tools"};
    
    for(i=0; i<4; i++){
        j = 0;
        while(*(*(strings+i)+j)){
            printf("[%d][%d][%c] ", i, j, *(*(strings+i)+j));
            j++;
        }
        printf("\n\n");
    }
    
    return 0;
    
}

It’s very easy to declare a pointer. Pointers are declared using the typical variable declaration format, with the addition of an asterisk placed between the data type and the variable’s identifier.

#include <stdio.h>

int main(void){
    
    double dare;
    double *pDare;
    
    
    dare = 169.254
            
    //use address of operator
    *pDare = dare;
    
    return 0;
    
}

The address of operator, &, returns its operand’s memory address.

Note that the asterisk that declares a variable as a pointer is the same symbol used for multiplication. It’s also used in dereferencing a pointer.

#include <stdio.h>

int main(void){
    
    int anum = 1024;
    //declare pointer
    int *apointer;
    
    //assign pointer a memory address
    apointer = &anum;
    
    printf("Address of anum = %p Value = %d\n", &anum, anum);
    printf("Address of apoiter = %p Value = %d\n", &apointer, *apointer);
    
    return 0;
    
}

Note that the %p specifier is used to display pointer values.

Want to learn more? Get my book http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

I also have a book on the Linux command line, only $.99 http://www.amazon.com/Big-Als-Linux-Fedora-CLI-ebook/dp/B00GI25V30/

 

 

 

 

Introduction to Bitwise Operators

Bitwise operators operate on the bits in integer values. There are six bitwise operators in all:

& Bitwise AND operator

| Bitwise OR operator

^ Bitwise EOR (Exclusive Or) operator

~ Bitwise NOT operator

>> Bitwise shift right operator

<< Bitwise shift left operator

The ~ operator is a unary operator; all of the other bitwise operators are binary operators. The bit-not ~ operator is thus perhaps the simplest example. The ~ operator flips the bits of its operand, changing the 1 bits to 0 and the 0 bits to 1.

#include <stdio.h>

int main(void){
    
    unsigned int i = 0;

    printf("%u\n", ~i);
    printf("%u\n", i);
    
    return 0;
    
}

The shift operators shift the bits in the left operand by the number of positions specified by the right operand. The left shift operator, <<, moves the bits to the left. Arithmetically, the left-shift operator is equivalent to multiplication by a power of two.

In the following program, we will shift a single 1 bit to the left to produce powers of two.

#include <stdio.h>

int main(void){
    
    unsigned int i = 1;
    int j = 0;
    
    for(j; j<8; j++){
        printf("%d\t", 1 << j);
    }

    putchar('\n');

    return 0;
    
}

The right shift operator moves bits to the right. This is an operation best done on unsigned integers.

#include <stdio.h>

int main(void){
    
    unsigned char i = 16;
    
    printf("%d\n", 16);

    i = i >> 2;

    printf("%d\n", 16 >> 2);

    i = i >> 2;

    printf("%d\n", 16 >> 4);

    return 0;

}

We can also use the binary bitwise operators in assignments, excluding, of course, the unary operator ~.

#include <stdio.h>

int main(void){

    int i = 1;
    int j = 1;
    i <<= 3;

    printf("i = %d\n", i);

    i >>= 2;

    printf("i = %d\n", i);

    return 0;

}

The bitwise AND operator, &, examines the bits of its two operands in parallel, and places a one in the position where both bits are 1, and a zero in all other positions. The bitwise OR operator, |, places a one in any position where either operand has a one.

#include <stdio.h>

int main(void){

    int i = 1;
    int j = 1;
    int k = 1;

    printf("1 << 7 = %d \t 1 << 6 = %d\n", 1 << 7, 1 << 6);
    printf("3 << 6 = %d \n", 3 << 6);
    printf("(1 << 7) + (1 << 6) = %d\n",
            (1 << 7) + (1 << 6));

    i <<= 7;
    j <<= 6;

    k = i | j;

    printf("i = %d \t j = %d\n", i, j);
    printf("k = i | j\n");
    printf("k = %d\n", k);

    k &= j;

    printf("k &= j\n");
    printf("k = %d\n", k);

    return 0;

}

Bitwise operators might seem a bit academic, but they’re used often enough. One use is to store multiple values in a single variable, which is how Linux file permissions are stored.

Arguments to main() in C

Sometimes we want to pass information into a program from the OS. Generally, we pass information to the main() function via command line arguments. A command line argument is the information we place after the program’s name when starting the program from the command line.

There are two special arguments, argc and argv, that are used to receive command line arguments. The argc parameter is an int value that holds the number of arguments being passed to main(). The argv parameter is a pointer to an array of character pointers. Each element in this array points to a command line argument, which is a string of char values.

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

int main(int argc, char **argv){
        
        if(argc!=2){
            printf("You need to provide your name as an argument.\n");
            exit(1);
        } else {
            //name is the second value pointed to
            //by argv
            printf("Hello %s\n", *(argv+1));
        }
        
    return 0;
    
}

Note that each command line argument should be separated by a space or a tab. We can provide a string with spaces as a single argument by enclosing in quotation marks. For instance, when running the program above from the command line, I entered ./exe “Al Jensen” to have my full name printed.

The most common way to declare argv is char *argv[]. The empty brackets indicate that the array’s length is unknown. We can access the individual arguments either via array indexing or pointer arithmetic. The following program will print out every argument sent to it from the command line.

#include <stdio.h>

int main(int argc, char *argv[]){
    
    int i = 0;
    
    /*
     * print out all the arguments received
     * from the OS
     */
    while(i<argc){
        /*
         * offset i by + 1
         * so arguments aren't numbered
         * from zero
         */
        printf("argument %d: \t %s\n",
                i+1, argv[i]);
        i++;
        
    }
    
    return 0;
    
}

Here is another program example, which counts down to ignition. The count is specified by the user on the command line. The atoi() function is used to convert the string value passed in from the OS to a integer value.

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

int main(int argc, char *argv[]){
    
    int count;
    
    /*
     * check to make sure enough arguments have
     * been provided
     */
    if(argc<2){
        printf("Please enter the length of the countdown.\n");
        exit(1);
    }
    
    /*
     * use atoi function to convert
     * string to integer
     */
    for(count=atoi(argv[1]); count; count--){
        printf("%d... \t", count);
    }
    
    printf("\nBlastoff!!!\n");
    
    return 0;
}

To access an individual character in one of the command line aguments, we add a second index to argv.

#include <stdio.h>

int main(int argc, char *argv[]){
    
    int i, j;
    
    for(i=0, j=0; i<argc; i++){
        while(argv[i][j]){
            printf("[%c]", argv[i][j++]);
        }
        putchar('\n');
        j = 0;
    }
    
    
    i=0;    
    
    /*
     * using pointer arithmetic to accomplish
     * the same thing
     */
    while(i<argc){
        j=0;
        printf("%s\n", *(argv+i));
        while(*(*(argv+i)+j)){
            printf("-%c-", *(*(argv+i)+j));
            j++;
        }
        i++;
        putchar('\n');
    }
    
    return 0;

}

Remember that for argv the first index access the entire string, and the second index accesses the individual char elements.

Interested in learning more? Get over 200 example programs for your Amazon Kindle or Kindle app: http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

Arrays as Arguments to Functions

Passing an argument to a function becomes more complicated when the argument is an array.  When we pass an array as an argument, the argument does not receive the contents of the array. Instead, the address of the initial element of the array is passed.

#include <stdio.h>
#define ARRAYSIZE 5

void printArray(int array[]);

int main(void){
    
    int array[ARRAYSIZE] = {3, 9, 27, 81, 243};
    
    printArray(array);
    
    return 0;
    
}

void printArray(int array[]){
    int i = 0;
    while(i < ARRAYSIZE){
        printf("element %d = %d\n", i, array[i]);
        i++;
    }
}

The value of strings lies in the fact that a string, which is really a char array, has a terminating character. Therefore, we do not need to pass the length of the array to a called function.

#include <stdio.h>

int stringLength(char s[]);

int main(void){
    char string1[]="Is that a real poncho or a Sear's poncho?";
    char string2[]="You are technically correct - the best kind of correct.";
    
    printf("%s has %d characters\n",
            string1, stringLength(string1));
    
    printf("%s has %d characters\n", string2, stringLength(string2));
    
    return 0;
}


int stringLength(char s[]){
    int i = 0;
    
    /*
     * search for terminating null
     */
    for(i; s[i]!='';i++){;}
    
    /*
     * i is now the lenth of the string
     */
    return i;
    
}

The crucial point is to not think of the parameter inside the called function as an array of characters, but as a variable that holds the address of the initial element in the array. The technical term for such a variable is a character pointer.

#include <stdio.h>

#define STRLENGTH 100
void stringCopy(char *targString, char *srcString);

int main(void){

    char string1[STRLENGTH] = "I solemnly swear that I am up to no good.";
    char string2[STRLENGTH];
    
    stringCopy(string2, string1);
    
    printf("%s\n", string2);
    printf("%s\n", string1);
    return 0;
    
}

void stringCopy(char *targString, char *srcString){
    
    while(*srcString){
        /*
         * parentheses in expression below
         * not actually necessary, but...
         */
        *(targString++) = *(srcString++);
    }
    *targString = '';
}

The stringCopy() function above copies the characters from one char array to another.

Interested in learning C? Take a look at my book, that contains over 200 all-new sample programs: http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/