Skip to main content

Declarations

Exercises

Question 18.1

For each of ihe following declarations, identify the storage class, type qualifiers, type specifiers, declarators, and initializers.

  1. static char **lookup(int level);
  2. volatile unsigned long io_flags;
  3. extern char *file_name [MAX_FILES] , path[];
  4. static const char token_buf[] = "";

The following properties are avaiable for:

  1. What is the variable lookup: It is a function which returns a pointer to a pointer to a type of static char. The following properties are:

    • storge class: static (function has internal linkage)
    • type qualifiers: none
    • type specifiers: char
    • declarators: **lookup(int level) - function which takes in an int parameter as argument, and returns a pointer to a pointer.
    • initializers: none
  2. What is the variable io_flags: It is a variable of:

    • storage class: none
    • type qualifiers: volatile
    • type specifiers: unsigned long
    • delcarators: io_flags
    • initializers: none
  3. What is the variable file_name and path:

    • storage class: extern (static storage duration)
    • type qualifiers: none
    • type specifiers: char
    • declarators: *file_name[MAX_FILE] - an array of pointers of size MAX_FILE, and path is (wrongly) defined as an array of unknown size without any initialization.
    • initializers: none
  4. What is the variable token_buf:

    • storage class: static
    • type qualifiers: const
    • type specifiers: char
    • declarators: token_buf[]
    • initializers: "" - an empty string

Question 18.2

Answer each of the following questions with auto, extern, register, and/or static.

  1. Which storage class is used primarily to indicate that a variable or function can be shared by several files?
  2. Suppose that a variable x is to be shared by several functions in one file but hidden from functions in other files. Which storage class should x be declared to have?
  3. Which storage classes can affect the storage duration of a variable?
  1. The keyword extern can be used to share a variable or function with multiple files. (Functions are implicitly defined to be of extern storage class)
  2. x should have a file scope as well as internal linkage. This can be achieved using the static keyword.
  3. Inside the block, using the keyword static can make sure that the variable has static storage duration rather than automatic storage duration. Likewise, using extern can achieve the static storage duration inside the block. Using auto outside the function and in global scope is illegal. register is has no effect on the storage duration.

Question 18.3

List the storage duration (static or automatic), scope (block or file), and linkage (internal, external, or none) of each variable and parameter in the following file:

extern float a;

void f(register double b)
{
static int c;
auto char d;
}

The following order of properties of variable are in the form (variable_name -> storage class, scope, linkage)

  1. astatic, file, ? (probably external)
  2. bautomatic, block, none
  3. cstatic, block, none
  4. dautomatic, block, none

Question 18.4

Let f be the following function. What will be the value of f(10) if f has never been called before? What will be the value of f(10) if f has been called five times previously?

int f(int i)
{
static int j = 0;
return i * j++;
}

In the scenario that f has never been called previously and the first call is f(10), the following value is returned by f:

10 * 0, and after that, j is incremented (post increment).

After one call, j will be 1, the second call changes j from 1 to 2, and in the fourth call, j would have the value 4, and if f(10) is called, the value of j will be 10 * 4 (j will be five after the the function returns) -> 40.


Question 18.5

State whether each of the following statements is true or false. Justify each answer.

  1. Every variable with static storage duration has file scope.
  2. Every variable declared inside a function has no linkage.
  3. Every variable with internal linkage has static storage duration.
  4. Every parameter has block scope.
  1. False. A variable declared inside a function with the keyword static has static storage duration, but no file scope.
  2. False. A variable declared inside a function with the keyword extern may have internal or external linkage. If the variable has been previously defined as static, then it has internal linkage, else it has external linkage.
  3. True. Usually, variables declared outside any function with the keyword static has internal storage duration. When we define variable in this manner, the variable will have static storage duration.
  4. True. A parameter will have block scope. Also, it is illegal to specify static/extern/auto to parameters. register has block scope.

Question 18.6

The following function is supposed to print an error message. Each message is preceded by an integer, indicating the number of times the function has been called. Unfortunately, the function always displays 1 as the number of the error message. Locate the error and show how to fix it without making any changes outside the function.

void print_error(const char *message)
{
int n = 1;
printf("Error %d: %s\n", n++, message);
}

The error with this code fragment is that n is a variable that has automatic storage duration, i.e. n is defined only when the function is called. After the function reaches the enclosing braces (}), the variable n does not exist, hence after calling the function another time, the variable will hold 1.

To make the code behave as stated in question, we need to declare the storage class of variable n as static.


Question 18.7

Suppose that we declare x to be a const object. Which one of the following statements about x is false?

  1. If x is of type int, it can be used as the value of a case label in a switch statement.
  2. The compiler will check that no assignment is made to x.
  3. x is subject to the same scope rules as variables.
  4. x can be of any type.
  1. False. While x is type-qualified to be a "const", it does not mean that x is now a constant expression. It merely means that x is stored in a memory location that can be "read-only". This is why, x cannot be used in a constant expression. #66 of chapter's note gives a better explaination.
  2. True. variables qualified as "const" can only be initialized, not assigned.
  3. True. when a variable is declared const inside a block, the variable will have block scope. If the variable which is defined outside any functions, it will have a file scope.
  4. True. const is a type qualifier, which is one of the declaration specifiers (storage class, type qualifiers, and type specifiers) when declaring a variable.

Question 18.8

Write a complete description of the type of x as specified by each of the following declarations.

  1. char (*x[10])(int);
  2. int (*x(int))[5];
  3. float *(*x(void)) (int);
  4. void (*x(int, void (*y)(int)))(int);
  1. x is an array of pointers of size 10 that has elements of type functions pointer that takes in an integer as an argument and returns a character.
  2. x is a function that takes in integer as an argument and returns a pointer to an array of type integer of size 5.
  3. x is a function that takes in no argument and returns a pointer to a function that takes an integer and returns a pointer of type float.
  4. x is a function which takes in two arguments: an integer and a pointer to a function that has integer as an argument and returns void, returns a pointer to a function that takes an integer as an argument and returns void.

Question 18.9

Use a series of type definitions to simplify each of the declarations in Exercise 8.

*** Beginning of Question 8(a) *** The number provided is: 10 *** End of Question 8(a) *** *** Beginning of Question 8(b) *** Element 0 is: 10 Element 1 is: 11 Element 2 is: 12 Element 3 is: 13 Element 4 is: 14 *** End of Question 8(b) *** *** Beginning of Question 8(c) *** The number 10 in floating format is: 10.00 *** End of Question 8(c) *** *** Beginning of Question 8(d) *** Statements from function z The provided number is: 10 The function question_d was called with the integer 10 Ending the function z Calling from the function main The function question_d was called with the integer 10 *** End of Question 8(d) ***


Question 18.10

Write declarations for the following variables and functions:

  1. p is a pointer to a function with a character pointer argument that returns a character pointer.
  2. f is a function with two arguments: p, a pointer to a structure with tag t, and n, a long integer, f returns a pointer to a function that has no arguments and returns nothing.
  3. a is an array of four pointers to functions that have no arguments and return nothing. The elements of a initially point to functions named insert, search, update, and print.
  4. b is an array of 10 pointers to functions with two int arguments that return structures with tag t.
#include <stdio.h>
#include <stdlib.h>

/* Question 10(a) */
char *print_and_return_string(char *str);

/* Question 10(b) */
struct t {
int n;

Question 18.11

In Section 18.4, we saw that the following declarations are illegal:

int f(int)[];       /* functions can't return arrays */
int g(int)(int); /* functions can't return functions */
int a[10](int); /* array elements can't be functions */

We can, however, achieve similar effects by using pointers:afunctioncanreturnapointerto the first element in an array, a function can return a pointer to a function, and the elements of an array can be pointers to functions. Revise each of these declarations accordingly.

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

#define MALLOC_IS_NULL(addr) \
if(!(addr)) { \
fprintf(stderr, "[ERROR] Memory Allocation Failed. Exiting.\n"); \
exit(EXIT_FAILURE); \
}

Question 18.12

  1. Write a complete description of the type of the function f, assuming that it's declared as follows:

int (*f(float (*)(long), char *))(double);

  1. Give an example showing how f would be called.

f is a function which takes in two parameters:

  1. a pointer to a function which takes in a long as an argument and returns a float
  2. a pointer to char

and returns a pointer to a functions which has an argument of type double and returns an integer.


Question 18.13

Which of the following declarations are legal? (Assume that PI is a macro that represents 3.14159.)

  1. char c = 65;
  2. static int i = 5, j = i * i;
  3. double d = 2 * PI;
  4. double angles[] = {0, PI / 2, PI, 3 * PI / 2};

Based on my understanding,

  1. is legal. char is one byte 'int' like data type. char - which defaults to signed in normal scenario - has the value range from -128 to 127, while unsigned char can store values from 0 to 255.
  2. is legal. Although it might seem like initialization of j seems to have Undefined behavior since i is initialized in the same line, but as of my understanding, a comma is considered a sequence point, hence the value will be successfully initialized before being utilized by the initializtion of variable j.
  3. is legal. Assigning PI (which is a macro that represents a double literal) * 2, will result in a value of type double (implicit conversion, check chapter 7).
  4. is legal. angles is an array of type double, and the values stored will be double, even if it is an integer literal, will be converted to double due to implicit conversion.

Actual Output: Seems like all but (ii) was right. Apparently, initializer must be a compile time constant. This is true, as i is not a constant. And initializing variable j with variable is illegal. Check #45(1) of Chapter's notes.


Question 18.14

Which kind of variables cannot be initialized?

  1. Array variables
  2. Enumeration variables
  3. Structure variables
  4. Union variables
  5. None of the above

It may seem like the answer is (e), as we can initialize all the types of variables mentioned. But, in C99, Variable-Length Arrays (VLAs) cannot be initialized, it can only be declared. Once the size of the array is determined, the array can then be assigned values. I'm not entirely sure about this, but structures having flexible array members may face some errors during initialization.


Question 18.15

Which property of a variable determines whether or not it has a default initial value?

  1. Storage duration
  2. Scope
  3. Linkage
  4. Type

Scope and Linakge (as mentioned in the #64 of Chapter's notes) are for compiler and linker respectively. Scope defines the range in which the variable can be used - either block or file, whereas, Linkage defines the variables which can be shared among files (external), used in the only file defined (internal) or none (blocks/auto). Type has no relevance as it defines the type specification of the variable. Storage duration, on the other hand, can be used to determine if the variable has a default value. As mentioned in #46(2) of Chapter's notes, a variable of storage class static has the default value zero.