CSCI-UA.
0201
Computer Systems Organization
C Programming – Pointers, Structs, Arrays
Thomas Wies
wies@[Link]
[Link]
Pointers:
Very powerful but also
dangerous concept!
Can a function modify its arguments?
What if we wanted to implement a function pow_assign() that
modified its argument, so that these are equivalent:
float p = 2.0; float p = 2.0;
/* p is 2.0 here */ /* p is 2.0 here */
p = pow(p, 5); pow_assign(p, 5);
/* p is 32.0 here */ /* p is 32.0 here */
Would this work?
void pow_assign(float x, uint exp)
{
float result=1.0;
int i;
for (i=0; (i < exp); i++) {
result = result * x;
}
x = result;
}
NO!
Remember the stack!
void pow_assign(float x, unsigned int exp)
{
float result=1.0; In C, all arguments are passed
int i;
for (i=0; (i < exp); i++) {
by value
result = result * x;
}
x = result;
} But, what if the argument is
main()
the address of a variable?
{
float p=2.0;
pow_assign(p, 5);
}
float x 2.0
32.0
uint32_t exp 5
float result 1.0
32.0
float p 2.0 Grows
Passing Addresses
Symbol Addr Value
0
1
2 address of x: 4
3 memory content at address 4: 72
char x 4 ‘H’ (72)
char y 5 ‘e’ (101)
6
7
8
9
10
11
12
“Pointers”
This is exactly how “pointers” work.
A “pointer type”: pointer to char
void f(char * p)
{
• address of x: &x *p = *p - 32;
• if y is an address, the }
content of the memory at char y = 101; /* y is 101 */
f(&y); /* i.e. f(5) */
that address: *y /* y is now 101-32 = 69 */
Pointers are used in C for many other purposes:
• Passing large objects without copying them
• Accessing dynamically allocated memory
• Passing functions to other functions
• Implement functions with multiple return values
Pointer Validity
A valid pointer is one that points to memory that your program controls.
Using invalid pointers will cause non-deterministic behavior, and will often
cause your OS to kill your process (SEGV or Segmentation Fault).
There are two general causes for these errors:
• Program errors that set the pointer value to an invalid address
• Use of a pointer that was at one time valid, but later became invalid
char * get_pointer() {
Will ptr be valid or invalid? char x=0;
return &x;
}
void foo() {
char * ptr = get_pointer();
*ptr = 12; /* valid? */
}
Answer: Invalid!
A pointer to a variable allocated on the stack becomes invalid when that
variable goes out of scope and the stack frame is “popped”. The pointer will
point to an area of the memory that may later get reused and rewritten.
char * get_pointer()
{
char x=0;
return &x;
} But now, ptr points to a
void foo()
{
location that’s no longer in use,
char * ptr = get_pointer(); and will be reused the next time
*ptr = 12; /* valid? */
other_function(); a function is called!
}
101 charaverage
int x Return
0 101
12
456603
100 char * ptr 101
? Grows
Now that we know about pointers, let’s go
back to types.
More on Types
We’ve seen a few types at this point: char, int, float, char *
Types are important because:
• They allow your program to impose logical structure on memory
• They help the compiler tell when you’re making a mistake
In the next slides we will discuss:
• How to create logical layouts of different types (structs)
• How to use arrays
• How to parse C type names (there is a logic to it!)
• How to create new types using typedef
Structures
• a collection of related data items
• possibly of different types
• defined using the keyword struct
• The members of a struct type variable are
accessed with the dot (.) operator:
<struct-variable>.<member_name>
struct basics
• Definition of a structure:
struct <struct-name> {
Each identifier
<type> <identifier_list>;
<type> <identifier_list>;
defines a member
... of the structure.
} ;
struct basics
• Example: main()
{
struct Address { Example struct Address addrs;
int zip; …
char street[50]; [Link] = 10012;
char city[20]; }
} ;
Example of
initializing a
structure
struct Address addrs = {10012, “Mercer”, “New York”};
Arrays
Arrays in C are composed of a particular type, laid out in memory in a
repeating pattern. Array elements are accessed by stepping forward in
memory from the base of the array by a multiple of the element size.
/* define an array of 5 chars */ Brackets specify the count of elements. Initial
char x[5] = {‘t’,’e’,’s’,’t’,’\0’};
values optionally set in braces.
/* accessing element 0 */
x[0] = ‘T’;
Arrays in C are 0-indexed (here, 0..4)
/* pointer arithmetic to get elt 3 */
char elt3 = *(x+3); /* x[3] */ x[3] == *(x+3) == ‘t’ (NOT ‘s’!)
/* x[0] evaluates to the first element;
* x evaluates to the address of the
Symbol Addr Value
* first element, or &(x[0]) */
char x [0] 100 ‘t’
/* 0-indexed for loop idiom */
#define COUNT 10 char x [1] 101 ‘e’
char y[COUNT]; For loop that iterates from char x [2] 102 ‘s’
int i;
for (i=0; i<COUNT; i++) { 0 to COUNT-1. char x [3] 103 ‘t’
/* process y[i] */ Memorize it!
printf(“%c\n”, y[i]); char x [4] 104 ‘\0’
}
Pointers and Arrays in C
• An array name by itself is an address, or
pointer in C.
• When an array is declared, the compiler
allocates sufficient space beginning with some
base address to accommodate every element
in the array.
• The base address of the array is the address of
the first element in the array (index position 0).
– Example: int num[10];
&num[0] is the same as num
Pointers and Arrays in C
• Suppose we define the following array and pointer:
int a[100]; int* ptr;
Assume that the system allocates memory at
addresses 400, 404, 408, ..., 796 to the array.
int values are allocated 32 bits = 4 bytes.
– The two statements: ptr = a; and ptr = &a[0]; are
equivalent and would assign the value of 400 to ptr.
• Pointer arithmetic provides an alternative to array
indexing in C.
– The two statements: ptr = a + 1; and ptr = &a[1]; are
equivalent and would assign the value of 404 to ptr.
Pointers and Arrays in C
• Assuming the elements of the array of integers
have been assigned values, the following code
would sum the elements of the array:
int sum = 0;
for (ptr = a; ptr < &a[100]; ++ptr)
sum += *ptr;
• Here is another way to sum the array:
int sum = 0;
for (i = 0; i < 100; ++i)
sum += *(a + i);
a[b] is just
syntactic sugar for *(a + b)
Strings
• Series of characters treated as a single unit
• Can include letters, digits, and certain special characters
(*, /, $)
• String literal (string constant) - written in double quotes
– "Hello"
• Strings are arrays of characters (type char[])
• String literals are implicitly terminated by a '\0'.
• Each character is represented in numerical code called ASCII
code.
• Example:
– char greeting[] = “Hello”;
– size of greeting is 6 (length of “Hello” + 1 for '\0').
– address of the above string can be expressed in two ways:
• &greeting[0]
• greeting
ASCII code
Strings
• String declarations
– Declare as a character array or a variable of type char *
char color[] = "blue";
char *colorPtr = "blue";
– Remember that strings represented as character arrays end with '\0'
• color has 5 elements
• Inputting strings
– Use scanf
scanf("%s", word);
• Copies input into word[], which does not need & (because a string is a
pointer)
– Remember to leave space for '\0'
Character Handling Library
• In <ctype.h>
Prototype Description
int isdigit( int c ) Returns true if c is a digit and false otherwise.
int isalpha( int c ) Returns true if c is a letter and false otherwise.
int isalnum( int c ) Returns true if c is a digit or a letter and false otherwise.
int isxdigit( int c ) Returns true if c is a hexadecimal digit character and false otherwise.
int islower( int c ) Returns true if c is a lowercase letter and false otherwise.
int isupper( int c ) Returns true if c is an uppercase letter; false otherwise.
int tolower( int c ) If c is an uppercase letter, tolower returns c as a lowercase letter. Otherwise, tolower
returns the argument unchanged.
int toupper( int c ) If c is a lowercase letter, toupper returns c as an uppercase letter. Otherwise, toupper
returns the argument unchanged.
int isspace( int c ) Returns true if c is a white-space character—newline ('\n'), space (' '), form feed
('\f'), carriage return ('\r'), horizontal tab ('\t'), or vertical tab ('\v')—and
false otherwise
int iscntrl( int c ) Returns true if c is a control character and false otherwise.
int ispunct( int c ) Returns true if c is a printing character other than a space, a digit, or a letter and false
otherwise.
int isprint( int c ) Returns true value if c is a printing character including space (' ') and false
otherwise.
int isgraph( int c ) Returns true if c is a printing character other than space (' ') and false otherwise.
Each function receives a character (an int) or EOF as an argument
String Conversion Functions
• Conversion functions
– In <stdlib.h> (general utilities library)
– Convert strings of digits to integer and floating-point
values
Prototype Description
double atof( const char *nPtr ) Converts the string nPtr to double.
int atoi( const char *nPtr ) Converts the string nPtr to int.
long atol( const char *nPtr ) Converts the string nPtr to long int.
double strtod( const char *nPtr, char Converts the string nPtr to double.
**endPtr )
long strtol( const char *nPtr, char Converts the string nPtr to long.
**endPtr, int base )
unsigned long strtoul( const char *nPtr, Converts the string nPtr to unsigned
char **endPtr, int base ) long.
String Manipulation Functions
• In <string.h>
• String handling library has functions to
– Manipulate string data
– Search strings
– Determine string length
Func tio n p ro to typ e Func tio n d esc rip tio n
char *strcpy( char *s1, Copies string s2 into array s1. The value of s1 is
const char *s2 ) returned.
char *strncpy( char *s1, Copies at most n characters of string s2 into array
const char *s2, size_t n ) s1. The value of s1 is returned.
char *strcat( char *s1, Appends string s2 to array s1. The first character of
const char *s2 ) s2 overwrites the terminating null character of s1.
The value of s1 is returned.
char *strncat( char *s1, Appends at most n characters of string s2 to array
const char *s2, size_t n ) s1. The first character of s2 overwrites the
terminating null character of s1. The value of s1 is
returned.
String Manipulation Functions
int strcmp ( const char * str1,
const char * str2 )
return value indicates
the first character that does
<0 not match has a lower value in
ptr1 than in ptr2
the contents of both strings
0 are equal
the first character that does
>0 not match has a greater value
in ptr1 than in ptr2