C Language Variables and Pointers Flashcards
Type Modifier
Change width of data types
Name of an array
Acts as the starting address where the array is stored in memory; the equivalent of an assembly label
Casting
allows programmer to forcibly convert one data type to another
typedef
allows you to give known type a new name typedef struct{ int numerator; int denominator; } fraction;
fraction my_frac;
Using typedef for basic types
typedef unsigned char BYTE;
BYTE b1;
Pointer
variable that can only contain the memory address of another variable.
Does not contain data, however variable at memory address might contain data.
Is a variable too with an own memory address, hence can have a pointer to a pointer
Always one line in memory
Dereference:
act of looking up the value that the pointer points to
& operator
the “address operator” in C. If it proceeds any variable, it will determine its runtime address.
void
officially a data type but really more of a keyword to indicate the absence of data
void* pointer:
a “typeless” pointer, so it can point to any type of data. One limitation is that it cannot be dereferenced; you would have to cast it to a typed pointer in order to dereference it. The void* pointer’s purpose is to allow for the passage of a memory address but not to allow dereferencing.
Implicit vs Explicit Cast
Smaller to bigger conversions are implicit; compiler does the casting for you:
int a = 5 ;
float b = 5.0 ;
b = a ; // implicit cast
Bigger to smaller conversions are not implicit; you must cast explicitly: int a = 5 ; float b = 5.0 ; a = (int)b ; // explicit cast, decimal is truncated // (fraction is lost – no rounding) ○ When going from bigger to smaller, the data is truncated so you must know what you are doing!
Why we need pointers in C:
○ One good use is to help us pass addresses to functions instead of data.
○ Recall that, in C, we pass copies of local variables to functions in order to ensure their local scope is protected.
○ Pointers allow us to “break scope” and send address of a local variable.
Pointers to arrays in C
Pointers vs Label
○ The difference:
■ The name of an array is a LABEL for an address in data memory that contains data.
■ A pointer is a VARIABLE that contains a memory address of a variable that contains data.
○ You can change the address held onto by a pointer.
■ You cannot change the address of an array (because it is essentially a label)! You were not able to change a Label in Assembly once set, why should you be able to do it in C.
○ You can use the [ ] operator as a dereferencing operator on a pointer.
■ Helpful if pointer points to an array
■ Don’t let that confuse you into thinking that a pointer is an array!
○ You can do pointer arithmetic on a pointer.
■ You cannot do pointer arithmetic on an array! See the above rules as to why.
○ Remember, an array’s name is basically the label for a memory address.
○ Passing the name of an array is the same as passing a memory address!
Why always initialize a pointer
You should always initialize a pointer in order to avoid unexpected behavior in your program.
Ways to define constants in C
#define you may change the next time you compile #define statements are like assembly directives i.e. don’t get space allocated ○ const types are for constants that “never change” e.g. pi ■ Note: const variables do have space allocated!
Const Modifier: Pointer to constant
We can change what the pointer points to but not the value of what it points to.
const char *ptr
Const Modifier: Constant pointer to a variable
We can’t change what pointer points to but we can change the value of what it points to.
char const *ptr
Constant pointer to a constant variable
■ We can’t change what pointer points to,
■ And we can’t change the value of what it points to!
const char const *ptr
3 basic regions of data memory in C:
○ Stack ■ Local variables, arguments, returns ○ Global/static region ■ Global vars, static vars ○ Heap ■ Dynamic space
2 Basic Storage Classes
○ Automatic variables lose their values when their block terminates (since they are on the stack).
■ Arguments, return types, local variables
○ Static variables retain values between invocations. note local variables can be declared static. Stored in Global region
■ Global variables are a type of static variable. -> stored in global region
Data types in C
char - 8 bits
int - 16/32/65 bits - 16 on LC4
float - 32 bits
double - 64 bits
Data modifiers to change width of data types
short - halves width
long - doubles width
unsigned - binary is unsigned
How many rows of data memory does a double take on lc4
4 as its addresswidth is 16 and a double takes 64bits space
Array
Name of array, like a label.
Labels first address of array.
Label cannot be changed. No pointer arithmetic possible
Stored like a giant variable. -> Stored consecutively in memory, in increasing order
index [I] matches offset from label
Cast types
Implicit: assign int variable to double variable
Explicit: assign double variable to int variable. -> Fraction is lost, no rounding
User defined types with struct only
struct fraction{
int a;
int b;
}
struct fraction myfrac;
myfrac. a = 3
myfrac. b = 4;
Without typdef need always to use struct keyword when creating new variable.
How to interpret:
int *ptr;
ptr is pointer that can only hold addresses at which location a int variable is stored.
-> pointers are typed
Why are pointers typed
So they can be dereferenced, reason why a pointer of type void cannot be dereferenced
When dereferencing, need to know how many loads to do, to get data from memory
Dereferencing in Assembly
2 Load Instructions
Load value of pointer from data memeory
Load value of variable pointer is pointing to from data memory
A pointer is typed in C so that when they are ‘dereferenced’ we load the right amount of information.
&
If it proceeds any variable, it will determine its runtime address
How to dereference a POINTER to user defined data types (struct)
(*ptr).component
easier
ptr->component
if it is just the variable name and not the pointer then
variable.component
Why we need pointers
break scope - help us pass addresses to functions instead of data
Make pointer point to array
int *var = &a[0];
int *var = a;
How does c pass an array to a function
Does NOT make a copy of the “local variable” as for regular variables but rather passes the address of the first element of the array.
-> You CANNOT pass a copy of an array in C -> function will mess with array in callers frame
int a[3] = {1,2,3}
funct( a); equivalent to funct( &a[0]) or funct(&a)
remember “label” ‘a’ stands for the memory address of the first element in the array. Hence, passing the name of an array is the same as passing a memory address
Reason: avoid unnecessary overhead and blowing up the stack
Can function determine length of array
there is no no way function can determine how long the array was that was passed to it. –> reason why passing in length of array to function as well
What happens if you dereference a pointer that was not initialized
segfault if value at pointers address is NULL or not of type of pointer
or
Unwanted behavior if by any chance at that location an address has been stored pointing to a variable of the type of the pointer
Can you return a pointer from a function
Not if that pointer was created in that function and was created on the stack and not in dynamic memory.
Reason the pointer we would return reference to something on stack that has been popped off once function returns
Why can we have a pointer of type void
Void is a dataype, hence we can have a pointer of this type.
C has no problem with it as pointers need the same amount of space, compiler can handle
However, you cannot dereference a void parameter
funct( void *ptr) Does not work if I do not cast ptr to a different type within the function
-> void only useful to pass memory addresses around
When to use #define, when to use const
Differences
#define like a directive does not use memory. Can change the value at the next compilation. When compiling, compiler will substitute this "directive" with the defined value -> Defined above main {}
Const: constants that never change. Const variables do have space allocated
defined within function.
Why use const in an argument list of a function
serves as an advertisment as to what a function will or will not do to the data you pass into it.
const -> will not change the data
With what are variables initialized
With nothing, unless they are global, static variables
in which case with 0;
static variables = retain values between calls
float num = 0.5;
Assembly Instructions to put on stack
- 5 -> IEEE -> 1.0 * 2 ^(-1) -> 0011 1111 0000….
- -> X3F00 X0000
- -> float takes up two rows each 16bits
ADD R6 R6 #-2; Update Stack Pointer
CONST R7 x00 ; Write lower part of lost number
HICONST R7 x00
STR R7 R5 #-1 ; Store lower part of float on stack
CONST R7 x00 ; Write uper part of lost number
HICONST R7 x3F
STR R7 R5 #-2 ; Store upper part of float on stack
Dereferencing in Assembly
- Load pointer from data memory (Address it is pointing to)
2. Load content from address pointer is pointing to.
Will following code work?
void square (void *var){ *var = (*var) * (*var); }
int main(){ int a = 10; square(&a) }
No.
Eventhough argument “&a” points to an address that holds an int, we will still get an error,
because the argument of square will be treated as if it is a void pointer, despite passing in a int pointer
A void pointer cannot be dereferenced
Hence, we need first to cast the void pointer to a int pointer within square to solve this
void square (void *var){ int *ptr = (int *) var; *ptr = (*ptr) * (*ptr); }
What value does local have at the end?
OPTION A: int main(){ int local = 20; { int local = 30; } }
OPTION B: int main(){ int local = 20; { local = 30; } }
OPTION A:
Still 20.
Local is a automatic variable that loses its value when their black terminates
OPTION B:
Within block not new variable is defined but the one from the outer block is updated.
What is wrong with this code
int main(){
int a;
a++;
}
a never initialized as local variable. Only global and static variables are automatically initialized with 0.
a++; will increment whatever value is currently stored at ‘a’ from previous operations
user start program calling main
.DATA
.ADDR x2000
USER_STACK_ADDR .UCONST x7FFF ; address where stack should start for users
.CODE ; adddress where USER_START should be loaded
.ADDR x0000
.FALIGN
USER_START
LC R6, USER_STACK_ADDR ; initialize the stack pointer (R6)
ADD R5, R6, #0 ; initialize the frame pointer (R5)
LEA R7, main
JSRR R7 ; invoke the main routine
END
What is printed?
int a = 1;
int main(){
printf(“Step1: %d\n”, a);
int a = 2;
printf(“Step2: %d\n”, a);
{
int a = 3;
printf(“Step3: %d\n”, a);
}
printf(“Step4: %d”, a);
}
Step 1: 1
Step 2: 2
Step 3: 3
Step 4: 2
Reason, C always used the definition of the most inner block.
Step 1 it is the global variable,
once local variable in main has been defined, it used the variable defined in scope main
and in step 3 it uses the variable defined in the subscope in main.
Use variable that has the respective name that is most up on the stack.
What does followinig code print out when user enters 8888
char label[10];
scanf(“%s”,label);
printf (“%s”, label);
8888
digits are also chars