Declarations
Exercises
Question 18.1
For each of ihe following declarations, identify the storage class, type qualifiers, type specifiers, declarators, and initializers.
static char **lookup(int level);volatile unsigned long io_flags;extern char *file_name [MAX_FILES] , path[];static const char token_buf[] = "";
- Answer
The following properties are avaiable for:
-
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
- storge class:
-
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
-
What is the variable
file_nameandpath:- storage class:
extern(static storage duration) - type qualifiers: none
- type specifiers: char
- declarators:
*file_name[MAX_FILE]- an array of pointers of sizeMAX_FILE, and path is (wrongly) defined as an array of unknown size without any initialization. - initializers: none
- storage class:
-
What is the variable
token_buf:- storage class:
static - type qualifiers:
const - type specifiers:
char - declarators:
token_buf[] - initializers: "" - an empty string
- storage class:
Question 18.2
Answer each of the following questions with auto, extern, register, and/or static.
- Which storage class is used primarily to indicate that a variable or function can be shared by several files?
- Suppose that a variable
xis to be shared by several functions in one file but hidden from functions in other files. Which storage class shouldxbe declared to have? - Which storage classes can affect the storage duration of a variable?
- Answer
- The keyword
externcan be used to share a variable or function with multiple files. (Functions are implicitly defined to be ofexternstorage class) xshould have a file scope as well as internal linkage. This can be achieved using thestatickeyword.- Inside the block, using the keyword
staticcan make sure that the variable has static storage duration rather than automatic storage duration. Likewise, usingexterncan achieve the static storage duration inside the block. Usingautooutside the function and in global scope is illegal.registeris 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;
}
- Answer
The following order of properties of variable are in the form (variable_name -> storage class, scope, linkage)
a→static,file, ? (probablyexternal)b→automatic,block,nonec→static,block,noned→automatic,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++;
}
- Answer
- Output
- Program
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.
Call 0 to the function f, and it returned 0 Call 1 to the function f, and it returned 10 Call 2 to the function f, and it returned 20 Call 3 to the function f, and it returned 30 Call 4 to the function f, and it returned 40
#include <stdio.h>
int f (int i) {
static int j = 0;
return i * j++;
}
int main (void) {
for (int i = 0; i < 5; i++) {
Question 18.5
State whether each of the following statements is true or false. Justify each answer.
- Every variable with static storage duration has file scope.
- Every variable declared inside a function has no linkage.
- Every variable with internal linkage has static storage duration.
- Every parameter has block scope.
- Answer
- False. A variable declared inside a function with the keyword
statichas static storage duration, but no file scope. - False. A variable declared inside a function with the keyword
externmay have internal or external linkage. If the variable has been previously defined as static, then it has internal linkage, else it has external linkage. - True. Usually, variables declared outside any function with the keyword
statichas internal storage duration. When we define variable in this manner, the variable will have static storage duration. - 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);
}
- Answer
- Output
- Program
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.
Error 1: [ERROR] Divide by Zero. Error 2: [ERROR] Memory Allocation Failed. Error 3: [ERROR] Segmentation Fault.
#include <stdio.h>
void print_error (const char *message) {
static int n = 1;
printf("Error %d: %s\n", n++, message);
}
int main (void) {
print_error("[ERROR] Divide by Zero.");
Question 18.7
Suppose that we declare x to be a const object. Which one of the following statements about x is false?
- If
xis of typeint, it can be used as the value of a case label in aswitchstatement. - The compiler will check that no assignment is made to
x. xis subject to the same scope rules as variables.xcan be of any type.
- Answer
- False. While
xis type-qualified to be a "const", it does not mean thatxis now a constant expression. It merely means thatxis stored in a memory location that can be "read-only". This is why,xcannot be used in a constant expression. #66 of chapter's note gives a better explaination. - True. variables qualified as "const" can only be initialized, not assigned.
- 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.
- 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.
char (*x[10])(int);int (*x(int))[5];float *(*x(void)) (int);void (*x(int, void (*y)(int)))(int);
- Answer
- Output
- Program
xis 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.xis a function that takes in integer as an argument and returns a pointer to an array of type integer of size 5.xis 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.xis 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.
The number provided is: 10 Element 0 is: 10 Element 1 is: 11 Element 2 is: 12 Element 3 is: 13 Element 4 is: 14 The number 10 in floating format is: 10.00 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
#include <stdio.h>
char question_a (int num);
int (*x(int))[5];
float *(*y(void)) (int);
float *question_c (int);
Question 18.9
Use a series of type definitions to simplify each of the declarations in Exercise 8.
- Output
- Program
*** 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) ***
#include <stdio.h>
char question_a (int num);
int (*x(int))[5];
float *(*y(void)) (int);
float *question_c (int);
Question 18.10
Write declarations for the following variables and functions:
pis a pointer to a function with a character pointer argument that returns a character pointer.fis a function with two arguments:p, a pointer to a structure with tagt, andn, a long integer,freturns a pointer to a function that has no arguments and returns nothing.ais an array of four pointers to functions that have no arguments and return nothing. The elements ofainitially point to functions namedinsert,search,update, andprint.bis an array of 10 pointers to functions with twointarguments that return structures with tagt.
- Program
- Output
#include <stdio.h>
#include <stdlib.h>
/* Question 10(a) */
char *print_and_return_string(char *str);
/* Question 10(b) */
struct t {
int n;
The string passed to print_and_return_string function is: Hello, World! The returned string is: Hello, World! The number stored inside the structure of tag t is: 10 The value of the long variable is: 100 The function do_nothing has the address: 0x4012ab The function do_nothing has the address: 0x4012ab Called the insert function. Called the search function. Called the update function. Called the print function. Added the 1 to the structure. Ignored 10
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.
- Program
- Output
#include <stdio.h>
#include <stdlib.h>
#define MALLOC_IS_NULL(addr) \
if(!(addr)) { \
fprintf(stderr, "[ERROR] Memory Allocation Failed. Exiting.\n"); \
exit(EXIT_FAILURE); \
}
***********************ARRAY*********************** [LOG] The address of the variable fixed_size_ptr_to_arr is: 0x32d56b0 Element 0 has the value: 100 Element 1 has the value: 100 Element 2 has the value: 100 Element 3 has the value: 100 Element 4 has the value: 100 Element 5 has the value: 100 Element 6 has the value: 100 Element 7 has the value: 100 Element 8 has the value: 100 Element 9 has the value: 100 [LOG] The address of the variable temp_unknown_array is: 0x32d56e0 Element 0 has the value: 0 Element 1 has the value: 1 Element 2 has the value: 4 Element 3 has the value: 9 Element 4 has the value: 16
***********************ARRAY***********************
*********************FUNCTION********************** [LOG] The function which called function ret_fcn_ptr is: main [LOG] The value stored in get_fcn_addr is: 0x40144e The secret number is: 10 [LOG] The function which called function ptr_to_fcn_ptr is: main The secret number (again) is: 10 [LOG] The function acc_to_question was called with argument: 10 [LOG] The function print_number was provided argument: 100
*********************FUNCTION**********************
************ARRAY OF FUNCTION POINTERS************* The address stored in the first element is: 0x4014e4
************ARRAY OF FUNCTION POINTERS*************
Question 18.12
- Write a complete description of the type of the function
f, assuming that it's declared as follows:
int (*f(float (*)(long), char *))(double);
- Give an example showing how
fwould be called.
- Answer
- Output
- Program
f is a function which takes in two parameters:
- a pointer to a function which takes in a long as an argument and returns a float
- a pointer to char
and returns a pointer to a functions which has an argument of type double and returns an integer.
#include <stdio.h>
float convert_long (long num);
int convert_double (double num);
int (*f (float (*pf) (long convert_to_float), char *test)) (double convert_to_int);
int main (void) {
int (*ret_ptr_to_fcn) (double);
*** Calling from f function ***
The result of calling convert_long with 5 as argument is: 5.000000 The provided string is: Hello, World!
*** End of Calling from f function ***
The value obtained from convert_to_int is: 10
Question 18.13
Which of the following declarations are legal? (Assume that PI is a macro that represents 3.14159.)
char c = 65;static int i = 5, j = i * i;double d = 2 * PI;double angles[] = {0, PI / 2, PI, 3 * PI / 2};
- Answer
- Output
- Program
Based on my understanding,
- 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.
- is legal. Although it might seem like initialization of
jseems to have Undefined behavior sinceiis 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 variablej. - 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). - is legal.
anglesis 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.
The value stored in c is: 65 The character stored in c is: A The value stored in i is: 5 The value stored in d is: 6.283180 Array variable angles and its subscript 0 has the value: 0.000000 Array variable angles and its subscript 1 has the value: 1.570795 Array variable angles and its subscript 2 has the value: 3.141590 Array variable angles and its subscript 3 has the value: 4.712385
#include <stdio.h>
#define PI 3.14159
int main (void) {
char c = 65;
static int i = 5/*, j = i * i*/;
double d = 2 * PI;
Question 18.14
Which kind of variables cannot be initialized?
- Array variables
- Enumeration variables
- Structure variables
- Union variables
- None of the above
- Answer
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?
- Storage duration
- Scope
- Linkage
- Type
- Answer
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.