COMP1511 17s1 Introduction to Programming
  1. No code review this week.
  2. What is this week's blogging theme?
  3. #include <stdio.h>
    
    int main(void) {
        char str[10];
        str[0] = 'H';
        str[1] = 'i';
        printf("%s", str);
        return 0;
    }
    
    1. What will happen when the above program is compiled and executed?
      The above program will compile without errors . printf, like many C library functions expects strings to be null-terminated.

      In other words printf, expects the array str to contain an element with value '\0' which marks the end of the sequence of characters to be printed.

      printf will print str[0] ('H'), str[1] then examine str[2].

      Code produced by dcc --valgrind will then stop with an error because str[2] is uninitialized.

      The code with gcc will keep executing and printing element from str until it encounters one containing '\0'. Often str[2] will by chance contain '\0' and the program will work correctly.

      Another common behaviour will be that the program prints some extra "random" characters.

      It is also possible the program will index outside the array which would result in it stopping with an error if it was compiled with dcc.

      If the program was compiled with gcc and uses indexes well outside the array it may be terminated by the the operating system because of an illegal memory access.

    2. How do you correct the program.
      #include <stdio.h>
      
      int main(void) {
          char str[10];
          str[0] = 'H';
          str[1] = 'i';
          str[2] = '\0';
          printf("%s", str);
          return 0;
      }
      
  4. Name 3 errors in this program:
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int
    main(void) {
        char line[MAX_LINE];
        int  i;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
            i = MAX_LINE;
            while (line[i] != '\n') {
                i = i - 1;
            }
            printf("line %d characters long\n", i);
        }
        return 0;
    }
    
    1. On the first execution of the inner while loop it accesses line[MAX_LINE] which is an illegal array index
    2. It accesses uninitialized array elements - fgets only assigns to the array elements necessary to hold the characters of a line plus a '\0'
    3. There may not be a '\n' in the array. fgets won't put a '\n' in the array if the line is too long to fit in the array. If there is no '\n' in the array the code will access an non-existent array element (line[-1]).
  5. Write a program line_length.c which reads lines from its input and prints how many characters each line contains.

    The only functions you can use are fgets and printf.

    You can assume lines contain at most 4096 characters.

    For example:

    ./line_length
    Andrew Rocks
    line 12 characters long
    A very long line.
    line 17 characters long
    short
    line 5 characters long
    
    line 0 characters long
    
    Sample solution for line_length.c
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int
    main(void) {
        char line[MAX_LINE];
        int  i;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
            i = 0;
            while (line[i] != '\n' && line[i] != '\0') {
                i = i + 1;
            }
            printf("line %d characters long\n", i);
        }
        return 0;
    }
    
    
    Heavily commented sample solutions for line_length.c
    // COMP1511 W9 tutorial question 5
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX 4096
    
    // prototype, returns an integers and takes in a string called line
    int count (char* line);
    
    int main (void) {
    
    	char line[MAX];	// holder for each line
    
    	while (fgets(line, MAX, stdin) != NULL) {
    		// so read in successfully
    		printf("line %d characters long\n", count(line));
    	}
    
    	return EXIT_SUCCESS;
    }
    
    int count (char* line) {
    	int i = 0;
    	while (line[i] != '\0') {
    		i++;
    	}
    	// exited when index i is the null terminating character
    	// so size is one less
    	i -= 1;
    	return i;
    }
    
  6. What do you use fopen for and with what parameters?
    If you want to read or write information to a file you need to use fopen to open the file first. You need to tell fopen the name of the file you wish to open and whether you want to open the file for reading ("r"), writing("w") or appending ("a"). Files that are opened for writing that already exist are truncated to size 0 (ie all contents are erased). So if you want to write information to a file but do not want to erase the current contents of the file you should use "a" append mode.

    If fopen is successful it returns a pointer to the file stream that has been opened, otherwise it returns NULL

  7. Under what circumstances would fopen return NULL?
    fopen returns NULL if the file you tried to open for reading does not exist. It will also return NULL if you try to open a file you do not have permission to access.
  8. Write a C code to read in the first line of a file named data.txt and display it on the screen.
    Sample solution (entire program)
    #include <stdio.h>
    
    #define MAX_LINE 1024
    
    int main(void) {
        char line[MAX_LINE];
        FILE *stream;
    
        stream = fopen("data.txt", "r");
        if (stream == NULL) {
            fprintf(stderr,"data.txt can't be opened for reading\n");
            return 1;
        }
        if (fgets(line, MAX_LINE, stream) != NULL) {
            printf("%s", line);
        }
        fclose(stream);  // unneeded
        return 0;
    }
    
    
    Heavily commented sample solutions.
    // COMP1511 W9 Tut Question 8
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX_LINE 4096
    
    int main (void) {
    	char line[MAX_LINE];	// holder for the line string
    	FILE *f;			// file pointer
    
    	f = fopen("data.txt", "r");
    	if (f == NULL) {
    		// couldn't open the file, print an error message
    		// to standard error
    		fprintf(stderr, "data.txt can't be opened for reading\n");
    		return EXIT_FAILURE;
    	}
    	// else you could read the file, display first line on scream
    	if (fgets(line, MAX_LINE, f) != NULL) {
    		printf("%s", line);
    	}
    
    	fclose(f);	// good practice
    	return EXIT_SUCCESS;
    }
    
    
  9. Write C code to read in a string from a user and write it to a file called data.txt. If the file data.txt exists, it should be overwritten
    Sample solution (entire program)
    #include <stdio.h>
    
    #define MAX_LINE 1024
    
    int main(void) {
        char line[MAX_LINE];
        FILE *stream;
    
        stream = fopen("data.txt", "w");
        if (stream == NULL) {
            fprintf(stderr,"data.txt can't be opened for writing\n");
            return 1;
        }
        fgets(line, MAX_LINE, stdin);
        fprintf(stream, "%s", line);
        fclose(stream); // necessary when writing to a file
        return 0;
    }
    
    
    Heavily commented sample solutions.
    // COMP1511 W9 Tutorial Question 9
    #include <stdlib.h>
    #include <stdio.h>
    
    #define MAX 4096
    
    int main (void) {
    
    	char line[MAX];
    	FILE *f;
    
    	f = fopen("data.txt", "w");
    
    	if (f == NULL) {
    		// error opening file
    		fprintf(stderr, "data.txt can't be opened for writing\n");
    		return EXIT_FAILURE;
    	}
    	// else read successfully, write text to file
    	fgets(line, MAX, stdin);	// get line from stdin
    	fprintf(f, "%s", line);		// write to file
    	fclose(f);
    
    
    	return EXIT_SUCCESS;
    }
    
    
  10. Write C to read in a string from a user and write it to a file called data.txt. If the file data.txt exists, it should append the line of text to the end of the file.
    Sample solution (entire program)
    #include <stdio.h>
    
    #define MAX_LINE 1024
    
    int main(void) {
        char line[MAX_LINE];
        FILE *stream;
    
        stream = fopen("data.txt", "a");
        if (stream == NULL) {
            fprintf(stderr,"data.txt can't be opened for writing\n");
            return 1;
        }
        fgets(line, MAX_LINE, stdin);
        fprintf(stream, "%s", line);
        fclose(stream); // necessary when writing to a file
        return 0;
    }
    
    
    Heavily commented sample solutions.
    // COMP1511 W9 Tutorial Question 10
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX 1024
    
    int main (void) {
    
    	char line[MAX];
    
    	// open file for appending
    	FILE *fp = fopen("data.txt", "a");
    	if (fp == NULL) {
    		fprintf(stderr, "data.txt can't be opened for writing.\n");
    		return EXIT_FAILURE;
    	}
    
    	// get line of input from user
    	printf("Enter a line of text:\n");
    	fgets(line, MAX, stdin);
    
    	// write it to the file
    	fprintf(fp, "%s", line);
    
    	// close the file
    	fclose(fp);	// necessary when writing to a file
    
    
    	return EXIT_SUCCESS;
    }
    
    

    Revision questions

    The remaining tutorial questions are primarily intended for revision - either this week or later in session.

    Your tutor may still choose to cover some of the questions time permitting.

  11. Write a program file_max.c that reads a set of integer numbers from a file and prints out the maximum number to standard output. The name of the input file should be specified as a command line argument.
    Sample solution for file_max.c
    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
        FILE *fp;
        int num;
        int max;
        int numbersRead;
    
        if (argc < 2) {
            fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
            return 1;
        }
    
        fp = fopen(argv[1], "r");
        if (fp == NULL) {
            fprintf(stderr, "%s: unable to open file %s,\n", argv[0], argv[1]);
            return 1;
        }
    
        numbersRead = 0;
        while (fscanf(fp, "%d", &num) == 1) {
            if (numbersRead == 0 || num > max) {
                max = num;
            }
            numbersRead = numbersRead + 1;
    
        }
    
        if (numbersRead > 0) {
            printf("Max : %d\n",max);
        }
    
        fclose(fp);
        return 0;
    }
    
    
    Heavily commented sample solutions.
    // COMP1511 W9 Tutorial Question 11
    #include <stdlib.h>
    #include <stdio.h>
    
    int main (int argc, char* argv[]) {
    
    	char *name;	// file name
    	FILE *f;	// file pointer
    
    	int num, max;	// number we're reading in, keep track of max number we've seen
    	int numRead = 0;	// counter for number of integers we've read in from file
    
    	// check that user specified file name as command line argument
    	if (argc < 2) {
    		// less than 2 command line arguments, so didn't specify filename
    		// print out helpful message
    		fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
    		return EXIT_FAILURE;
    	}
    	// file name in argv[1]
    	name = argv[1];	// redundant, this is just for readability
    	// open file for reading
    	f = fopen(name, "r");
    	if (f == NULL) {
    		// file opening error
    		fprintf(stderr, "%s: unable to open file %s\n", argv[0], name);
    		return EXIT_SUCCESS;
    	}
    
    	// everything is working fine now!
    	// read the numbers from the file
    	while (fscanf(f, "%d", &num) == 1) {
    		// is this the max number?
    		if (numRead == 0 || num > max) {
    			// either this is the first number
    			// or this number is greater than our max
    			max = num;
    		}
    
    		numRead++;
    	}
    
    	// print out max if you read in some numbers (so max initialized)
    	if (numRead > 0) {
    		printf("Max: %d\n", max);
    	}
    
    	// close file pointer, good practice
    	fclose(f);
    
    	return EXIT_SUCCESS;
    }
    
    
  12. Write a program strip_comments.c which reads lines from its input and prints them after removing any C // style comments. In another words if the line contains // it does not print the // or anything after it.

    The only functions you can use are fgets and printf.

    You can assume lines contain at most 4096 characters.

    For example:

    ./strip_comments
         x = x + 1;  // This means add one to the variable x
         x = x + 1;
    
    Also - is that a good comment to add to a C program?
    Sample solution for strip_comments.c
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int
    main(void) {
        char line[MAX_LINE];
        int  i;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
    
            // strip // style comments from input
    
            i = 0;
            while (line[i] != '\n' && line[i] != '\0') {
    
                // safe to look at line[i+1] because
                // we know here line[i] != '\0'
    
                if (line[i] == '/' && line[i + 1] == '/') {
    
                    // replace // with end of -line
                    line[i] = '\n';
                    line[i + 1] = '\0';
    
                    // could break here but loop will stop anyway
                }
    
                i = i + 1;
            }
    
            // write possibly-modified line
    
            printf("%s", line);
        }
        return 0;
    }
    
    
    Heavily commented sample solutions.
    // COMP1511 W9 Tut Question 12
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX 4096
    
    int main (void) {
    
    	char line[MAX];	// holder for each line
    	int i;	// counter for line
    
    	while (fgets(line, MAX, stdin) != NULL) {
    		// strip the // comments from input
    
    		// iterate through line and see if we encounter a '/' then '/'
    		// everything after is a comment, so stop the string there
    		i = 0;
    		while (line[i] != '\n' && line[i] != '\0') {
    
    			if (line[i] == '/' && line[i + 1] == '/') {
    				// found a comment, blank out this comment
    				line[i] = '\0';
    				break;
    			}
    
    			i++;
    		}
    
    		// print out edited(?) line to output
    		printf("%s\n", line);
    		// can print out '\n' or not
    		// depending on where the comment is (or if there's no comment)
    		// might have an extra blank line printed
    	}
    
    	return EXIT_SUCCESS;
    }
    
    
  13. Write a program filter_empty_lines.c which reads lines from its input and prints them only if they contain a non-white-space-character.

    In another words remove lines are empty or contain only white-space.

    The only functions you can use are fgets and printf.

    You can assume lines contain at most 4096 characters.

    You can assume there are only 3 white space characters, space, tab & new-line.

    For example:

    ./filter_empty_lines
    full line
    full line
             
    another no-empty line
    another no-empty line
    
    Sample solution for filter_empty_lines.c
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int
    main(void) {
        char line[MAX_LINE];
        int  i;
        int whiteSpaceCount;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
    
            // print lines iff they contain a non white-space character
    
            i = 0;
            whiteSpaceCount = 0;
            while (line[i] != '\0') {
                // test for white space (isspace would be better here)
    
                if (line[i] != ' ' && line[i] != '\t' && line[i] != '\n') {
                    whiteSpaceCount = whiteSpaceCount + 1;
                    // could break here
                }
    
                i = i + 1;
            }
    
            if (whiteSpaceCount > 0) {
                printf("%s", line);
            }
        }
        return 0;
    }
    
    
    Heavily commented sample solutions.
    // COMP1511 W9 Tut Question 13
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX 4096
    #define TRUE 1
    #define FALSE 0
    
    int main(void) {
    
    	char line[MAX];
    	int i;	// counter for iterating through line
    	int nonWhitespace;	// "boolean" value for if you've seen a whitespace char or not in this line
    
    	while (fgets(line, MAX, stdin) != NULL) {
    		// assume no whitespace
    		nonWhitespace = FALSE;
    		i = 0;
    		while (line[i] != '\n' && line[i] != '\0') {
    			if ((line[i] != ' ') && (line[i] != '\t') && (line[i] != '\n')) {
    				// this is a non-whitespace character
    				nonWhitespace = TRUE;
    				break;
    			}
    
    			i++;
    		}
    
    		// print the line if it has whitespace
    		if (nonWhitespace == TRUE) {
    			printf("%s", line);
    		}
    
    	}
    
    	return EXIT_SUCCESS;
    }
    
    
  14. Write a C program reverse.c which reads lines and writes them out with the characters of each line in reverse order. It should stop when it reaches the end of input.

    For example:

    ./reverse
    The quick brown fox jumped over the lazy dog.
    .god yzal eht revo depmuj xof nworb kciuq ehT
    It was the best of times. It was the worst of times.
    .semit fo tsrow eht saw tI .semit fo tseb eht saw tI
    This is the last line.
    .enil tsal eht si sihT
    <control-d>
    
    Sample solution for reverse.c
    #include <stdio.h>
    
    #define MAX_LINE 4096
    
    int
    main(void) {
        char line[MAX_LINE];
        int  i;
    
        while (fgets(line, MAX_LINE, stdin) != NULL) {
    
            i = 0;
            while (line[i] != '\n' && line[i] != '\0') {
                i = i + 1;
            }
    
            i = i - 1;
    
            while (i >= 0) {
                printf("%c", line[i]);
                i = i - 1;
            }
            printf("\n");
    
        }
        return 0;
    }
    
    
    Heavily commented sample solutions.
    // COMP1511 W9 Tutorial Problem 14
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX 4096
    
    int main(void) {
    
    	char line[MAX];
    	int i;	// counter for line
    	int size;	// size of this line
    
    	// get the lines
    	while (fgets(line, MAX, stdin) != NULL) {
    		// find the size of this line
    		i = 0;
    		while ((line[i] != '\n') && (line[i] != '\0')) {
    			// not the end yet
    			i++;
    		}
    		// when we exit, i is the index of newline or null terminating
    		size = i - 1;	// largest index of non-ending char
    
    		// now print in reverse
    		i = size;	// could get rid of size and jsut write i = i-1
    		while (i >= 0) {
    			printf("%c", line[i]);
    			i--;
    		}
    		// separate this line
    		printf("\n");
    	}
    
    	return EXIT_SUCCESS;
    }