Using the exec() Function in Unix-like Environments

The fork() function creates a new process. Using fork() is simple. Before we call the fork() function, one process, which we term the parent, exists. After we call the fork() function, there are two processes, the parent process and the child process. What can sometimes be confusing is that both processes continue to execute the same program!

However, we can distinguish between the two processes using a decision structure and the return value from the fork() function. The fork() function returns a negative value if it failed. In the child process, the fork() function returns 0. In the parent process, the fork() function returns the PID, which is always a positive integer.

#include <stdio.h>
#include <unistd.h>

int main(void){

    //pid_t is basically an int
    pid_t returnValue;

    if((returnValue = fork()) < 0){
        //error occured
        return -1;
    } 

    if(returnValue  == 0){
        printf("In the new process.\n");
        printf("process ID is %d\n", getpid());
    } 

    if(returnValue > 0){
        printf("In the parent process.\n");
        printf("process ID is %d\n", getpid());
    }

    return 0;

}

Note that PID values are unique; there cannot be two running processes with the same PID.

The exec() function starts a new program that retains the PID of the current process.

While exec() is referred to as being a single function, it is actually a family of functions with slightly different parameter lists and uses.

The simplest function in the exec() family to explain is execve(), since it is the underlying system call. The other functions are in fact wrapper functions.

The execve() function takes three arguments. The first argument is the path argument, this is the path to the executable file we want to execute. The second argument is argv, which is a full list of the arguments we wish to pass the executable file we specified in the first argument. Note that the second argument is an array of pointers, the first element of which should be the path of the program being executed.

#include <stdio.h>
#include <unistd.h>


int main(void){
    
    char *args[] = {"/bin/ls", NULL};

    execve("/bin/ls", args, NULL);


    return 0;

}

Like fork(), the exec() function is declared in the <unistd.h> header.

If exec() succeeds, it does not return to the caller, because exec() completely replaces the caller with the new program.

If exec() fails, it returns -1.

#include <stdio.h>
#include <unistd.h>

int main(void){

    
    char *args[] = {"/bin/ps", NULL};
    
    //check if exec works
    if(execve("/bin/ps", args, NULL) == -1){
        printf("Error with execve");
        return -1;
    }    


    return 0;

}

Remember, a call to exec() should not return, unless there was a problem. Commonly, if there is an error either the program requested doesn’t exist, or it exists but isn’t executable.

In our next program, we will create a child process. In both the parent and  child processes we will run execve() after knowingly passing it bad arguments. We will then examine the error numbers produced using the errno value.

#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main(void){

    char *args1[] = {"/bin/doesntexist", NULL};
    char *args2[] = {"/home", NULL};

    pid_t forkRVal;
    
    if((forkRVal=fork())<0){
        printf("problem forking");
    }        

    //in child process
    if(forkRVal==0){
        int execReturnVal;
        execReturnVal = execve("/bin/doesntexist", args1, NULL);    
        //execution will only reach this code
        //in the event of failure of execve()
        if(execReturnVal==-1){
            printf("In child process.\t");
            printf("Error no %d\n", errno);
        }
    }

    //in parent process
    if(forkRVal>0){
        int execReturnVal;
        execReturnVal = execve("/home", args2, NULL);
        //check if execve() failed    
        if(execReturnVal==-1){
            printf("In parent process.\t");
            printf("Error no %d\n", errno);
        }
    }

    return 0;

}

The execl() function is a wrapper function for execve(). The execl() function takes as its first argument the pathname of the file to execute. Following this first argument is a variable number of arguments to pass to the program being called. By convention, the second argument should be the name of the program. The list of arguments must be terminated by a NULL value so that execl() can tell where the argument list ends. The program called by execl() inherits the environment specified in the current program’s ENVIRON variable.

#include <stdio.h>
#include <unistd.h>
#include <errno.h>


int main(void){

    int retValue;

    retValue = execl("/bin/date", "date", NULL);
    
    if(retValue==-1){
        printf("Error no %d", errno);
    }

    return 0;

}

If you get the chance, please take a look at my author page on Amazon.com: http://www.amazon.com/Al-Jensen/e/B008MN382O/

Sorting and Processing Strings in C

An array of strings is stored in memory as a two dimensional array of characters. For our first program, we will create a two dimensional array of five words with each word containing up to ten characters.

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

int main(void){

    int i, j;

    char swapstring[10];

    char strings[5][10] = {
            {'T','e','l','e','b','i','t'},
            {'A','t','a','r','i'},
            {'M','e','m','o','t','e','c','h'},
            {'V','i','s','i','c','o','r','p'},
            {'B','o','m','i','s'},
        }; // end strings[][]   


    printf("The original list is: \n");
    for(i = 0; i < 5; i++){
        printf("%s\n", strings[i]);
    }
    printf("\n");

    //use bubble sort
    for(j = 0; j < 4; j++){
        for(i = j + 1; i < 5; i++){
            //strcmp() returns a number greater than zero
            //if the second string is less than the first
            if(strcmp(strings[j], strings[i]) > 0){
                strcpy(swapstring, strings[j]);
                strcpy(strings[j], strings[i]);
                strcpy(strings[i], swapstring);
            }
        }
    }

    printf("The sorted list is: \n");
    for(i = 0; i < 5; i++){
        printf("%s\n", strings[i]);
    }

    return 0;


}

In our first program we used bubble sort to sort the list of strings. A bubble sort is a nested loop that performs n-1 passes over a list of n number of items, swapping an item with the next item in the list if it is greater than the next item. Bubble sort is very simple, and also very inefficient.

In our next program, we will use selection sort to sort the strings. Selection sort’s main value over bubble sort is that it should in general perform less swaps; although, it is still not a very efficient sorting routine. Selection sort, like bubble sort, has an inner and outer loop. The outer loop moves from the start of the array to the penultimate element. At each increment of the outer loop, the inner loop sets the potential minimum value to whatever the current index is in the outer loop. The inner loop then compares this theoretical minimum value with every element after it; if the loop finds a value that is less than the theoretical minimum, it resets the the theoretical minimum to the index of that element. Finally, when the inner loop has been completed, it then and only then swaps out the current element in the outer loop with the element that the inner loop found to be the smallest.

 

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


int main(void){

    char swapstring[10];

    int j,k, minimum;

    char strings[5][10]= {
        "Malthus",
        "Smith",
        "Volaire",
        "Hobbes",
        "Hume"
    };

    printf("The original list is: \n");
    for(j = 0; j < 5; j++){
        printf("%s\n", strings[j]);
    }


    for(j = 0; j < 4; j++){
        //set index of smallest element
        minimum = j;
        for(k = j + 1;  k < 5; k++){
            //if result is negative
            //strings[k] is less than strings[minimum]
            if(strcmp(strings[k], strings[minimum]) < 0){
                //elemet at index k is new minimum
                minimum = k;
            }

        } //end innner for loop
       
        //swap
        strcpy(swapstring, strings[j]);
        strcpy(strings[j], strings[minimum]);
        strcpy(strings[minimum], swapstring);

    } // end outer for loop

    printf("The sorted list is: \n");
    for(j = 0; j < 5; j++){
        printf("%s\n", strings[j]);
    }

    return 0;
}

Our next program counts the number of vowels in a string using a simple switch statement.

#include <stdio.h>

#define LENGTH 50


int GetVowelCount(char *s);

int main(void)
{

    char string1[LENGTH] = "WelcoMe to ThE jUnGLe, we'VE got fuN aNd GAmes.";
    char string2[LENGTH] = "hE's THE One thEy call dR. FeELgoOd.";

    int i = 0;
   

    printf("Vowel count for %s: ", string1);
    printf("%d\n", GetVowelCount(string1));

    printf("Vowel count for %s: ", string2);
    printf("%d\n", GetVowelCount(string2));

    return 0;
}

int GetVowelCount(char *s){
    int i = 0, j = 0;

    while(*(s+i)!=''){
        switch(*(s+i)){
            case 'A':
            case 'a':
                j++;
                break;
            case 'E':
            case 'e':
                j++;
                break;
            case 'I':
            case 'i':
                j++;
                break;
            case 'O':
            case 'o':
                j++;
                break;
            case 'U':
            case 'u':
                j++;
                break;   
        }
        i++;
    }

    return j;
}

Our final program is a simple one as well; it is the classic palindrome checker. A palindrome is a word that reads the same forwards and backwards.

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

int CheckForPalindrome(char *s);

int main(void){

    char *s[5] =
    {
        “radar”,
        “robot”,
        “kayak”,
        “jazz”,
        “civic”,
    };

    for(int i = 0; i < 5; i++){
        printf(“%s\t”, *(s+i));
        if(CheckForPalindrome(*(s+i))>0){
            printf(“is a palindrome.\n”);
        } else {
            printf(“is not a palindrome.\n”);
        }
    }

    return 0;
}

//returns -1 if it finds two characters that do not match
//returns 1 otherwise
int CheckForPalindrome(char *s)
{
    int L = 0;
    //remember, index starts at 0
    //hence, minus 1
    int R = strlen(s) – 1;

    while(L < R){
        if(*(s+L)!=*(s+R)){
            return -1;
        }
        L++;
        R–;
    }

    return 1;
}

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

 

 

 

 

 

Simple Recursion in C

Certain objects in mathematics can be defined by the process that creates them, rather than as the end result itself. For instance, pi is defined as the ratio of the circumference of a circle to its diameter. When we think about it, pi is really defined as an algorithm – find out the circumference of a circle, then find out its diameter, then divide the circumference by the diameter. When we have an algorithm that produces a definite result, the algorithm itself can stand in for the result. In C, an algorithm that produces a result is a function, and, after all, we can in C and most C-family languages use a non-void function in place of a value, as long as the return type of the function is compatible with the type of the value we would have otherwise used.

Another example would be a factorial, represented as n!, where n is a positive integer. A factorial is defined as the product of all integers between the specified number and 0. For example, 3! = 3 * 2 * 1, which is equal to 6. While factorials are a pain to compute by hand, computers do them quite nicely, using a trusty loop.

#include <stdio.h>
int factorial(int n);
int main(void){ int num = 3; //3! printf("%d! = %d\n", num, factorial(num)); //increment num num++; //4! printf("%d! = %d\n", num, factorial(num)); printf("Note bene!:\n"); printf("%d! = %d * %d! ", num, num, num-1); printf("= %d\n", num * factorial(num-1)); return 0; }
int factorial(int n){ //use an iterative function for(int i = n - 1; i > 0; i--){ n*=i; } return n; }

 

Our first algorithm for producing a factorial is called an iterative algorithm; it calls for the repetition of a process until a condition is met. But, as we saw above, the factorial for a number is equal to that number multiplied by the factorial of the one less than itself. We can therefore describe a factorial as a chain produced by multiplying each positive number by the positive number before it; of course, this is verbally how we would describe the algorithm, but when it comes to writing it our first instinct is to write, for instance, 3! = 3 * 2 * 1, where we write the entire chain out at once. However, what if the number is 4, or 5, or 10, or 100?

We could generalize it as n! = n * n-1 * n-2 * etc etc * 1, or, strictly speaking, n! = n * n-1 * … * 1, with the three periods representing the implied intermediate values. As an easier shorthand, we can describe a factorial instead as n! = n * n-1!; this is a more exact representation of the verbal recipe we gave for arriving at a factorial – ‘multiply each whole number by the whole number preceding it, till we reach zero”. Defining an object in terms of a simpler case of itself is known as a recursive definition.

The thing is, though, doesn’t recursion go on forever? If Charlie Kaufman screenplays have taught us anything, it’s that the self-referential loop just goes backwards and backwards until we lose our minds.  Well, fear not, because just like an iterative loop, a recursion has a condition known as the base case that ends the loop. In the case of a factorial, !0 returns 1.

There’s an old joke that goes, “the key to understanding recursion is understanding recursion”. While humorous, this is, as far as I can tell, somewhat inaccurate, since there is no base case. In fact, in perhaps reinforces the false impression that recursion produces an infinite, self-referential loop. I would argue that a more useful reformulation would be “The key to understanding recursion is understanding recursion, unless you don’t understand recursion, in which case the key to understanding recursion is understanding the role of the base case, value-returning functions being treated as variables, and functions resolving first in, last out.” However, all that would probably not fit on a T-shirt.

#include <stdio.h>


int factorial(int n);

int main(void){
int n = 4;

printf("%d! = %d\n", n, factorial(n));

n--;

printf("%d! = %d\n", n, factorial(n));

return 0;

}


int factorial(int n){
//use a recursive function
if(n>1){
return n * factorial(n-1);
} else {
return 1;
}
}

One of the keys to grasping recursion in C is to remember that a value-returning function can be used in place of the value; this works because a called function must always resolve itself before the called function can resume executing.

Another fun example is to define the multiplication of positive integers recursively. Multiplication is, after all, just a weird kind of addition. If we take x * y, we see that it is really x plus itself y times.

#include <stdio.h>

int multiply(int x, int y);
//recursive version
int multiplyRecursively(int x, int y);

int main(void){
int n = 10;

for(int i = 1; i <= 10; i++, n--){
printf("%d * %d = %d\n", i, n, multiply(i, n));
printf("%d * %d = %d\n", i, n, multiplyRecursively(i, n));
}

return 0;
}

//iterative function
int multiply(int x, int y){
int val = x;
while(y-- > 1){
val+=x;
}
return val;
}

//recursive function
int multiplyRecursively(int x, int y){
if(y > 1){
return x + multiplyRecursively(x, y-1);
} else {
return x;
}
}

As our final example, we will take a look at the Fibonacci sequence.  The Fibonacci sequence is when we get a number by adding the two previous numbers in the sequence, and to start the sequence off, the first number is 0 and the second number is 1. Thus, the sequence goes 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, … We can view a Fibonacci sequence as being a function, we are willing to define f(0) as equalling 0 and f(1) as equalling 1; in other words, in the case of 0 or 1 the function returns its argument.

What about 2? Well, f(2) = 1 + 0, which also happens to be f(1) + f(0), so we can say that f(2) = f(1) + f(0). What about 3? Well, f(3) = 1 + 1, which happens to also be f(2) + f(1), thus we can say f(3) = f(2)+f(1), remembering here that f(2) = 1 and f(1) = 1. What about 4? Well, f(4) = 2 + 1, and since f(3) = 2 and f(2) = 1, we can say that f(4) = f(3) + f(2). For any element in the sequence, then, we can say that f(n) = f(n-1) + f(n-2), where f(0) = 0 and f(1) = 1. Or, if we really, really want to, we can say that f(n) = f(n-1) + f(n-2), where f(n) = n if n = 0 or n = 1.

#include <stdio.h>

int fib(int a);

int main(void){

for(int i = 0; i < 10; i++){
printf("Fib. num. for %d is %d\n", i, fib(i));
}

return 0;

}

int fib(int a){

if(a <= 1){
return a;
} else {
return fib(a-1) + fib(a-2);
}
}

Do you have $2.99 and a tablet, computer, or Kindle? Purchase a copy of my book on C, it’s viewable on just about any glowing screen you can think of. Over 100 example programs and explanations that are, I swear, far more lucid that the ones you find on this blog. http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

 

 

 

Basic POSIX Process Creation

Each process is identified by a number known as the process ID, or pid for short. The pid for the first process is 1, and each subsequent process is assign a new, unique positive integer. It’s a relatively simple matter to get the process ID number for the current process. The getpid() function returns the current function and the getppid() function returns the parent’s ID. Both functions return the pid_t data type, which is an int.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void){
    
    pid_t thisPID = getpid();
    pid_t parentPID = getppid();
    
    printf("PID of current process: %d\n", thisPID);
    printf("PID of parent process: %d\n", parentPID);
    
    return 0;
    
}

Note that the pid_t type is defined in the header file <sys/types.h>.

In Linux, processes form a  hierarchy known as the process tree. Traditionally, the first process is known as init; we can confirm this by issuing the bash command ps aux | head in a terminal or pseudo-terminal. New processes are created with the fork() system call; this system call takes no arguments and creates a duplicate of the calling process. The duplicate is called the parent, and the original process is called the child. If fork() fails, it returns -1.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void){
    
    fork();
            
    //prints twice
    printf(“Saluton Mundo!\n”);
    
    fork();
    
    //prints four times
    printf(“Greetings, Professor Falken.\n”);
    
    return 0;
    
}

Note that processes execute in parallel. Both the parent and child processes continue executing the remaining statements in the program. If the fork() function returns a value less than 0, we know that the function call has failed.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void){
    
    if((fork())<0){
        printf("fork failed.\n");
        exit(1);
    } else {
        printf("Fork succeded!");
        sleep(1);
        exit(0);
    }
    
    return 0;
    
}

The fork() function is unusual in that it returns two different values. The return value in the child process is zero, but the return value in the parent process is the process ID of the new child.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void){
    pid_t pid;
    
    if((pid=fork())<0){
        printf("problem forking.\n");
        exit(1);
    }else if (pid==0){
        printf("In the child process.\n");
    } else {
        printf("In the parent process.\n");
    }
    
    return 0;
    
}

Alright, let’s tie it all together in one altogether nifty example.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void){
    
    pid_t child;
    
    if((child=fork())<0){
        printf("Problem with fork()\n");
        exit(1);
    } else if (child == 0){
        printf("In child process, parent ID %d\n", getppid());
        printf("In child process, process ID %d\n", getpid());
    } else {
        printf("In parent process, process ID %d\n", getpid());
    }
    
    return 0;
    
}

 

Dynamic Memory and Pointers in C

One of the blessings (some would say curse) of C is the degree to which we are able to micromanage dynamic memory in C.  By allocating and deallocating memory dynamically our programs can execute with greater flexibility and efficiency. Liked lists and queues, for instance, would be impossible to implement without dynamic memory allocation. The use of pointers is integral to tracking dynamically allocated memory in C.

Dynamic memory allocation in C begins with the use of malloc() or a similar function to allocate memory. This memory is then used by the program via a pointer. Finally, we deallocate the memory use the free() function.

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

int main(void){
    
    double *d = (double*)malloc(sizeof(double));
    int *i = (int*)malloc(sizeof(int));
    
    *i = 2600;
    *d = 5.11;

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

    return 0;
    
}

The malloc() function accepts an argument that specifies the number of bytes to allocate. The malloc() function then returns a pointer to the memory allocated on the heap, unless it fails, in which case it returns a null pointer.

It’s important to be mindful of when we should and shouldn’t use the dereference operator with pointers to dynamic memory.

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

int main(void){
    
    long long *longlong;
    char *c;
    
    
    longlong = (long long*) malloc(sizeof(long long));
    c = (char*) malloc(sizeof(char));
    
    *longlong = 56007800;
    *c = 'd';
    
    printf("%lld\n", *longlong);
    printf("%c\n", *c);
    
    return 0;
   

Finally, we must always remember to use the free() function to deallocate the memory when it is no longer needed. Unlike memory allcoated on the stack, we must explicitly free up the memory when we are done with it. Every time the malloc() function is called, we must at some point issue a corresponding call to the free() function.

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

int main(void){
    
    int *a;
    double *b;
    char *c = (char *) malloc(sizeof(char));
    
    b = (double *) malloc(sizeof(double));
    a = (int *) malloc(sizeof (int));
    
    
    *a = 845;
    *b = 846.847;
    *c = 'd';
    
    printf("%d\t%f\t%c", *a, *b, *c);
    
    //important!!!
    free(a);
    free(b);
    free(c);
    
    return 0;
    
}

If we do not remember to use the free() function, we can have memory leaks. A memory leak happens with allocated memory is never used again but is not free.  This represents, at the very least, an inefficient use of system memory, and at worst can cause the program to crash. Memory leaks can also occur if we assign the pointer to a new memory location without freeing the memory it was previously pointing to.

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


int main(void){
    
    int *i = (int*) malloc(sizeof(int));
    
    *i = 42;
    
    printf("%d", *i);
    printf("\t(%p)\n", i);
    
    //whoops!
    i = (int*) malloc(sizeof(int));
    
    printf("%d", *i);
    printf("\t(%p)\n", i);
    
    free(i);
    
    return 0;
    
}

In our final program, we will allocate memory to store a string. We will use then use the strcpy() function to store a string of characters in the allocated memory space. We can then output the string to the console using printf() with the %s conversion specifier.

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

int main(void){
    
    char *s = (char *) malloc(sizeof(char)*15);
    
    //note strcpy() function
    //is in string.h header file
    strcpy(s, "Saluton Mundo!");
    
    printf("%s\n", s);
    
    free(s);
    
    return 0;
    
}

I have a couple Kindle books for sale at Amazon; they’re readable both on a Kindle as well as by using the Kindle app on tablet or computer: http://www.amazon.com/Al-Jensen/e/B008MN382O/

 

 

 

 

 

 

 

Function Return Values and Prototypes In C

Let’s look at ways to write function return values so as to increase our program’s effectiveness.

Return values enable us to pass data back from a receiving function to its calling function. When we want to return a value from a function to its calling function we put the return value after the return statement.

Note that we must include a function prototype in our program. In C, a function prototype models the function so as to inform the compiler of each function’s parameter list and return type. Prototyping a function is easy; all we need to do is copy the function’s header to the top of our program. We ought to recall here that the function header contains the return type, the function name, and the type of each argument sent to the function.

#include <stdio.h>

double average(int nums[], int arraySize);

int main(void){

    int nums[3];

    int avg, i;

    for(i = 0; i < 3; i++){
        printf("Please enter a number: ");
        scanf(" %d", &nums[i]);
        printf("%d number entered.\n", i + 1);
    }

    printf("The average is: %f\n", average(nums, 4));

    return 0;

}


//function returns a double value
double average(int nums[], int arraySize){
    int total;
    double count = arraySize;
    while(arraySize >= 0){
        total += nums[arraySize--];    
    }
                        
    return total / count;
}

Note that the prototypes for library functions are contained in header files, such as stdio.h and string.h.

We must always precede a function name with its return data type. Because the variable returned from the average() function above is a double, the double return type was placed before the function’s name when we defined the function. Note that we can only return a single value to a calling function.

We can place a call to a function on the right side of an assignment operator since the program replaces a function call with its return value when the return takes place. In a sense, a function that returns a value becomes that value.

#include <stdio.h>

int SquareNum(int num);

int main(void){
    
    int num;
    
    int square;
    
    printf("What number do you want squared?\n");
    scanf(" %d", &num);
    
    //assign return value to
    //the int variable square
    square = SquareNum(num);
    
    printf("%d squared is %d\n", num, square);
    
    
    return 0;
    
}

int SquareNum(int num){
    return num * num;
}

It is possible to nest function calls within other function calls.

#include <stdio.h>

//function prototype
double linearFunction(int rise, int run, int x, int b);

int main(void){
    
    int rise, run, intercept;
    
    printf("Enter the rise: ");
    scanf(" %d", &rise);
    
    printf("Enter the run: ");
    scanf(" %d", &run);
    
    printf("Enter the y-intercept: ");
    scanf(" %d", &intercept);
    
    for(int i = 0; i < 10; i++){
        printf("f(%d) = ", i);
        printf("%f\n", linearFunction(rise, run, i, intercept));
    }
    
    
    return 0;

}

double linearFunction(int rise, int run, int x, int b){
    return ((double)rise/run)*x+b;
}

Note that sometimes it is clearer to call the function and assign its return value to a variable before using it.

Our next program finds the digit sum of a number given by the user. The digit sum is all of the whole numbers from one to a certain number added together. We will also call a user-defined function from within another user-defined function for the first time.

#include <stdio.h>

int DigitSum(int num);
void printNumber(int i, int num);

int main(void){
    int num;
    printf("Enter a number: ");
    scanf(" %d", &num);
    
    printf("The digit sum of %d is %d\n", num, DigitSum(num));

}

int DigitSum(int num){

    int i;
    int sum;

    if(num <= 0){
        return num;
    } else {
        for(i=1, sum=0;i<=num;i++){
            //call another user defined function
            printNumber(i, num);
            sum+=i;
        }
    }

    return sum;
} //end DigitSum()

//prints either number +
//or else just the number
void printNumber(int i, int num){
    if(i<num){
        printf("%d + ", i);
    } else {
        printf("%d\n", i);
    }
}// end printNumber()

Note that when we prototype a function that does not return a value we declare it to be of type void.

If you’d like to learn more about C, take a look at my book that contains 300 new incremental lessons on C:

http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M