Week 09 Tutorial Questions

Objectives

  1. Write a C program, chmod_if_public_write.c, which is given 1+ command-line arguments which are the pathnames of files or directories

    If the file or directory is publically-writeable, it should change it to be not publically-writeable, leaving other permissions unchanged.

    It also should print a line to stdout as in the example below

    dcc chmod_if_public_write.c -o chmod_if_public_write
    ls -ld file_modes.c file_modes file_sizes.c file_sizes
    -rwxr-xrwx 1 z5555555 z5555555 116744 Nov  2 13:00 file_sizes
    -rw-r--r-- 1 z5555555 z5555555    604 Nov  2 12:58 file_sizes.c
    -rwxr-xr-x 1 z5555555 z5555555 222672 Nov  2 13:00 file_modes
    -rw-r--rw- 1 z5555555 z5555555   2934 Nov  2 12:59 file_modes.c
    ./file_modes file_modes file_modes.c file_sizes file_sizes.c
    removing public write from file_sizes
    file_sizes.c is not publically writable
    file_modes is not publically writable
    removing public write from file_modes.c
    ls -ld file_modes.c file_modes file_sizes.c file_sizes
    -rwxr-xr-x 1 z5555555 z5555555 116744 Nov  2 13:00 file_sizes
    -rw-r--r-- 1 z5555555 z5555555    604 Nov  2 12:58 file_sizes.c
    -rwxr-xr-x 1 z5555555 z5555555 222672 Nov  2 13:00 file_modes
    -rw-r--r-- 1 z5555555 z5555555   2934 Nov  2 12:59 file_modes.c
    
    Make sure you handle errors.
  2. Consider the lseek(fd, offset, whence) function.

    1. What is its purpose?

    2. When would it be useful?

    3. What does its return value represent?

  3. Consider a file of size 10000 bytes, open for reading on file descriptor fd, initially positioned at the start of the file (offset 0). What will be the file position after each of these calls to lseek()? Assume that they are executed in sequence, and one will change the file state that the next one deals with.

    1. lseek(fd, 0, SEEK_END);
    2. lseek(fd, -1000, SEEK_CUR);
    3. lseek(fd, 0, SEEK_SET);
    4. lseek(fd, -100, SEEK_SET);
    5. lseek(fd, 1000, SEEK_SET);
    6. lseek(fd, 1000, SEEK_CUR);
  4. Write a C program, print_diary.c, which prints the contents of the file $HOME/.diary to stdout

    The lecture example getstatus.c shows how to get the value of an environment variable.

    snprintf is a convenient function for constructing the pathname of the diary file.

  5. Write a C program, print_file_bits.c, which given as a command line arguments the name of a file contain 32-bit hexadecimal numbers, one per line, prints the low (least significant) bytes of each number as a signed decimal number (-128..127).
  6. What does the following printf(3) statement display?

    printf ("%c%c%c%c%c%c", 72, 101, 0x6c, 108, 111, 0x0a);
    

    Try to work it out without simply compiling and running the code. The ascii(7) manual page will help with this; read it by running man 7 ascii. Then, check your answer by compiling and running.

  7. Recall the UTF-8 encoding for characters below:

    Why did UTF-8 replace the ASCII coding standard? What is the difference in how ASCII and UTF-8 codepoints are represented in bytes?

  8. Write a C program that reads a null-terminated UTF-8 string as a command line argument and counts how many Unicode characters (code points) it contains. Assume that all codepoints in the string are valid. Some examples of how your program should work:

        dcc count_utf8.c -o count_utf8
        ./count_utf8 "チョコミント、よりもあなた!"
        there are 14 codepoints in the string
        ./count_utf8 "早上好中国现在我有冰淇淋"
        there are 12 codepoints in the string
        ./count_utf8 "🤓🤓🤓🤓🤓🤓🤓🤓"
        there are 8 codepoints in the string
        

  9. For each of the following calls to the fopen() library function, give an open() system call that has equivalent semantics relative to the state of the file.

    1. fopen(FilePath, "r")
    2. fopen(FilePath, "a")
    3. fopen(FilePath, "w")
    4. fopen(FilePath, "r+")
    5. fopen(FilePath, "w+")

    Obviously, fopen() returns a FILE*, and open() returns an integer file descriptor. Ignore this for the purposes of the question; focus on the state of the open file.

  10. If a file xyz contains 2500 bytes, and it is scanned using the following code:

    int fd;         // open file descriptor
    int nb;         // # bytes read
    int ns = 0;     // # spaces
    char buf[BUFSIZ]; // input buffer
    
    fd = open ("xyz", O_RDONLY);
    assert (fd >= 0);
    while ((nb = read (fd, buf, 1000)) > 0) {
        for (int i = 0; i < nb; i++)
            if (isspace (buf[i]))
                ns++;
    }
    close (fd);
    

    Assume that all of the relevant #include's are done.

    How many calls with be made to the read() function, and what is the value of nb after each call?

Extra questions

The following questions are extra content not necessarily needed to cover this week's content.
Your tutor may still choose to cover some of these questions, time permitting.

  1. The following code will compile with

    gcc   void-pointer.c -o void-pointer
    clang void-pointer.c -o void-pointer
    dcc   void-pointer.c -o void-pointer
    

    It will even compile with

    gcc   -Werror -Wall -Wextra void-pointer.c -o void-pointer
    clang -Werror -Wall -Wextra void-pointer.c -o void-pointer
    dcc   -Werror -Wall -Wextra void-pointer.c -o void-pointer
    

    But it wont compile with

    gcc   -Werror -Wall -Wextra              -Wpedantic void-pointer.c -o void-pointer
    clang -Werror -Wall -Wextra -Weverything -Wpedantic void-pointer.c -o void-pointer
    dcc   -Werror -Wall -Wextra              -Wpedantic void-pointer.c -o void-pointer
    

    How can the code be modified to compile with the -Wpedantic option?

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    static uint16_t a;
    
    int main(void)
    {
        uint16_t b;
    
        uint16_t *pa = &a;
        uint16_t *pb = &b;
        uint16_t *pc = malloc(sizeof(uint16_t));
    
        *pa = 0xAAAA;
        *pb = 0xBBBB;
        *pc = 0xCCCC;
    
        printf("a:\n\tvalue: 0x%X\n\taddress: %16p\n", *pa, pa);
        printf("b:\n\tvalue: 0x%X\n\taddress: %16p\n", *pb, pb);
        printf("c:\n\tvalue: 0x%X\n\taddress: %16p\n", *pc, pc);
    }
    
  2. The following code will compile with

    gcc   pointer-arithmetic.c -o pointer-arithmetic
    clang pointer-arithmetic.c -o pointer-arithmetic
    dcc   pointer-arithmetic.c -o pointer-arithmetic
    

    It will even compile with

    gcc   -Werror -Wall -Wextra pointer-arithmetic.c -o pointer-arithmetic
    clang -Werror -Wall -Wextra pointer-arithmetic.c -o pointer-arithmetic
    dcc   -Werror -Wall -Wextra pointer-arithmetic.c -o pointer-arithmetic
    

    But it wont compile with

    gcc   -Werror -Wall -Wextra              -Wpedantic pointer-arithmetic.c -o pointer-arithmetic
    clang -Werror -Wall -Wextra -Weverything -Wpedantic pointer-arithmetic.c -o pointer-arithmetic
    dcc   -Werror -Wall -Wextra              -Wpedantic pointer-arithmetic.c -o pointer-arithmetic
    

    How can the code be modified to compile with the -Wpedantic option?

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    void *next_byte(void *byte){
        return byte + 1;
    }
    
    int main(void)
    {
        uint8_t  chars[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        uint32_t ints[10]  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
        printf("%16p - %16p\n", (void *)&chars[0], (void *)next_byte(&chars[0]));
        printf("%16p - %16p\n", (void *)&ints[0],  (void *)next_byte(&ints[0]));
    }
    

Revision questions

The following questions are primarily intended for revision, either this week or later in session.
Your tutor may still choose to cover some of these questions, time permitting.