0% found this document useful (0 votes)
18 views9 pages

SE2S 2006 Pointers - 4up

The document discusses pointers in C including pointer variables, the address operator, pointer dereferencing, and the relationship between pointers and arrays. It also provides examples of using pointers to pass arguments and simulate call by reference.

Uploaded by

M. Murali
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views9 pages

SE2S 2006 Pointers - 4up

The document discusses pointers in C including pointer variables, the address operator, pointer dereferencing, and the relationship between pointers and arrays. It also provides examples of using pointers to pass arguments and simulate call by reference.

Uploaded by

M. Murali
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.

8 93 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.21 106

Pointers The Address Operator &


• A pointer is a memory address int y = 5;
int * yPtr ;
• Pointer variables are variables whose values are memory addresses

• Referencing a value though a pointer is called indirection yPtr = &y:

• Pointer variable declaration in C: • The operand of & must be a variable

int * countPtr, count; Confusing Declaration! • & can not be applied to


– constants
– countPtr is a variable of type “int *”, i.e., a pointer to an int
– expressions
– count is a variable of type int.
– register variables

• Type rule: If e has type t , then &e has type t *.

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.17 102 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.31 116

Use of Pointers in C The Pointer Dereferencing Operator *


Pointers are a low-level mechanism that allows to simulate important high-level int y = 5;
constructs: int * yPtr ;

• call by reference
yPtr = &y;
• (certain) subarrays
printf ( "%d\n", *yPtr );
• recursive datastructures
*yPtr = 7;
• graph-like datastructures printf ( "%d\n", y);

• higher-order functions The dereferencing operator, applied to a pointer value p, returns the variable p
points to, i.e.,
But: Pointers must be used very carefully! • in an expression: the contents of the memory address p
• to the left of an assignment: the variable at memory address p

Make sure p points to a sensible address!

Type rule: If e has type t *, then *e has type t


SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.35 120 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.37 122

Simulate Execution! — 1 Simulate Execution! — 3


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

void swap(int * p, int * q) void swap(int * p, int * q)


{ {
int h = *p; *p += *q;
*p = *q; *q −= *p;
*q = h; *p += *q;
} *q = 0 − *q;
}
int main () {
int i=4, j=7; int main () {
swap( &i, &j ); int i=4, j=7;
printf ("i = %d; j = %d\n", i, j); swap( &i, &j );
return 0; printf ("i = %d; j = %d\n", i, j);
} return 0;
}

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.36 121 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.47 132

Simulate Execution! — 2 Relationship between Pointers and Arrays


#include <stdio.h> Arrays are like
• const pointers
void swap(int * p, int * q)
{ • for which the size of space pointed to is known
int h = *p;
Assume:
*p = *q;
double b[5];
*q = h;
} double * bPtr ;
bPtr = b;
int main () { Then:
int i=4, j=7; • bPtr == &b[ 0 ]
swap( &i, &i );
• bPtr + 1== &b[ 1]
printf ("i = %d; j = %d\n", i, j);
return 0;
• *(bPtr + 3) == b[ 3 ]
} • bPtr + 3 == b + 3
• bPtr [ 1] == b[ 1]
SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.50 135 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.56 141

Arrays of Strings Command-Line Arguments: char **argv


#include <stdio.h> • The array char *argv[] contains argc+1 elements.
int main() { • argv[argc] == NULL
const char * suit[4] = {"Hearts", "Diamonds", "Clubs", "Spades"};
• Some people declare their main functions with int main(int argc, char **argv)
int i;
for (i = 0; i < 4; i++) printf ("suit[%d] = %p\t: “%s”\n", i, suit[i], suit[i]); • This declares the intent to use argv as the beginning of a
printf ("suit[2][3] = ‘%c’\n", suit[2][3]); NULL-terminated “string of pointers”
suit[3] = "Shovels"; #include <stdio.h> // argvS.c
for (i = 0; i < 4; i++) printf ("suit[%d] = %p\t: “%s”\n", i, suit[i], suit[i]); int main(int argc, char *argv[]) {
return 0; char ** argp;
} argp = argv;
while ( *argp ≠ NULL ) {
• char * suit[4] — an array of char * values printf ("argv[%d] = %p\t: “%s”\n", argp − argv, *argp, *argp);
• char * values interpreted as beginning of zero-terminated character strings argp++;
}
• Can be considered as an array of arrays — suit[2][3] works. return 0;
• Subarrays can be anywhere — nothing is known about relative arrangement in }
memory of suit[2] and suit[3]

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.55 140 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.57 142

Command-Line Arguments Experiment: Flipping Command-Line Arguments


#include <stdio.h> // argv.c #include <unistd.h> // flip.c
int main(int argc, char *argv[]) {
int i; int main(int argc, char * argv[]) {
for (i = 0; i ≤ argc; i++) char * newargv[argc];
printf ("argv[%d] = %p\t: “%s”\n", i, argv[i], argv[i] ? argv[i] : ""); int i;
return 0; for(i=1; i ≤ argc; i++) newargv[i−1] = argv[i]; // copying argv
} if (argc ≥ 4) {
newargv[1] = argv[3];
• The command line consists of space-separated words:
newargv[2] = argv[2];
– the command, and return execvp(argv[1], newargv);
– arguments }
• argv contains the whole command line else return 1;
• char * argv[] can be used as an array with argc elements: }
– argv[0] is the command, and
– argv[1] … argv[argc−1] are the arguments
– the number of arguments is (argc−1)!
• char ** argv can also be used as the beginning of a
NULL-terminated “string of pointers”
SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.59 144 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.68 153

const The sizeof Operator


const variables cannot be assigned to — but still have addresses: sizeof is a keyword used like a function that accepts as single argument
#include <stdio.h> – any variable, or
int main () { – any type,
const int n = 42; and returns an integral value of type size_t indicating
printf ("%d %p\n", n, &n); – how many bytes are reserved for the given variable, or
return 0;
– how many bytes are reserved for variables of the given type.
}
Note: For array variables this yields sizeof(element_type) * array_size.

General rules:
• a byte has 8 bits
• in C, characters are 8-bit integral values
• on a n-bit architecture, int and pointers occupy n bits, i.e., n/ 8 bytes
• (double variables occupy twice as much space as floats)
• long occupies not less space than int

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.60 145 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.74 159

const and Pointers Pointer Expressions and Pointer Arithmetic


For pointer arithmetic, a T-pointer ptr should be understood as an
int * p; p contains a non-constant pointer to non-constant data
“abstract index into memory considered as an array of T-variables”
const int * p; p contains a non-constant pointer to non-constant data Therefore:
int * const p; p contains a non-constant pointer to non-constant data • ptr + 1 is “the next index” — it points to the next T-variable
• when considering pointers as integers (for example when printing with “%p”)
const int * const p; p contains a non-constant pointer to non-constant data
the difference between ptr + 1 and ptr is: sizeof(T )
• for pointers of the same type (e.g. after ptrB = ptr + n;)

• constant: read-only one may calculate the pointer difference ptrB − ptr , which will be n.

• non-constant: variable, read-write Other pointer arithmetic operators:


• “+=”, “−=”, “++”, “−−”
SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.76 161 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.83 168

void Pointers Local Variables Must Not Escape Their Scope!


void * ptr ; #include <stdio.h> /* locstring.c */
• ptr is a void pointer — a “raw address” #include <string.h>

• any pointer value can be assigned to ptr char * reverse(int length, char * string) {
• ptr can be assigned to any pointer variable char result[length+1];
int i,j;
• void pointers are used as “pointers to anything” — faking polymorphism for ( i = length−1, j=0; i ≥ 0; i−−, j++ ) result[j] = string[i];
result[length] = ’\0’;
• void pointers cannot be dereferenced — a cast is necessary first
return result;
#include <stdio.h> }
int main() {
char s[] = "Hello World!"; int main() {
void * p = s; char msg1[] = "Hello world!";
void * q = p + 1; char * msg2;
printf ("%d “%s”\n", sizeof(void), (char *)q); msg2 = reverse(strlen(msg1), msg1);
return 0; printf ("Reversing finished!\n");
} printf ("msg2=‘%s’\n", msg2);
return 0;
}

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.82 167 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.91 176

NULL Stack vs. Heap


• NULL is defined in stdio.h as the zero-value for pointers • Local variables, function arguments, return values, and return addresses are
• NULL must not be dereferenced kept in stack frames on the execution stack
• NULL is the only pointer value for which you can determine in a safe way that
you are not allowed to dereference it • The stack “grows” and “shrinks” with the number of nested function calls.
• The presence of NULL allows pointers to be used as optional references: • Consecutive function calls use the same stack space.
Each pointer value – either is a reference to a variable
– or is NULL • Therefore, if a “new variable” needs to be accessible after a function returns, it
cannot be allocated on the stack.
void myInit(int * p) { /* p is either a reference or NULL */
if (p ≠ NULL) { • The heap is the space for dynamic data:
p = getLogLines(logfile); – void *malloc(size_t size) allocates size bytes on the heap and returns a pointer
log("Initialisation message: New run\n"); to the allocated memory (from stdlib.h).
}
else – void free(void *ptr ) frees the memory space pointed to by ptr, which must
unlink(logfile); have been returned by a previous call to malloc().
}
SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.92 177 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.104 189

strdup Parameterised Sorting Using Function Pointers


#include <string.h> int leq(double x, double y) { return x ≤ y; }
int geq(double x, double y) { return x ≥ y; }
char *strdup(const char *s);
void sort(double a[], const int size, int (*compare)(double x, double y))
The strdup() function returns a pointer to a new string which is a duplicate of the {
...
string s. Memory for the new string is obtained with malloc(3), and can be freed
if ( (*compare)(a[i], a[i+1]) ) {
with free(3). ...
} else {
The strdup() function returns a pointer to the duplicated string, or NULL if ...
insufficient memory was available. }
...
}

int main() {
...
sort(b, SIZE, leq);
...
}

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.103 188 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.106 192

Pointers to Functions Exercise: count_maximum


int leq(double x, double y) { return x ≤ y; } Design and implement a C function count_maximum that, given an int array,
int geq(double x, double y) { return x ≥ y; }
• finds the maximum element in this array
This defines two functions:
• at runtime, functions are machine code fragments, stored at some address • with respect to an ordering passed to count_maximum as a function pointer
• therefore, at run-time. the name leq is bound to an address argument,
• leq is a function pointer value • and also counts how many times this maximum occurs,
• leq can be passed as argument to functions, or assigned to pointer variables
• The type of a variable or argument compare accepting binding to leq is: • and makes both the maximum and this count available to its caller.

int (*compare)(double x, double y) • The array should be traversed only once!


• Full prototype:
void sort(double a[], const int size, int (*compare)(double x, double y));
• Short prototype: void sort(double[], const int, int (*)(double x, double y));
• Use of function pointer: if ( (*compare)(a[i], a[i+1]) ) ...
• Invocation: sort(b, SIZE, leq);
SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.107 193 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.118 204

String Initialisation and Modification The Character Handling Library (ctype.h)


#include <stdio.h> int isdigit(int c); /* checks for a digit (0 through 9) */
int isalpha(int c); /* checks for an alphabetic character */
char a[] = "Hello world!"; int isalnum(int c); /* checks for an alphanumeric character;
char * p = a; equivalent to (isalpha(c) || isdigit(c)) */
char * s = "Hello world!"; int isxdigit(int c); /* checks for a hexadecimal digits, i.e. one of
0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F */
int main () { int islower (int c); /* checks for a lower-case character */
a[5] = ’~’; int isupper (int c); /* checks for an uppercase letter */
int toupper (int c); /* converts the letter c to upper case, if possible */
printf ("p = %s\n", p); int tolower (int c); /* converts the letter c to lower case, if possible */
p[5] = ’_’; int isspace(int c); /* checks for white-space characters.
printf ("p = %s\n", p); In the C and POSIX locales, these are: " \f\n\r\t\v") */
int iscntrl(int c); /* checks for a control character */
printf ("s = %s\n", s); int ispunct(int c); /* checks for any printable character which is
s[5] = ’_’; not a space or an alphanumeric character */
printf ("s = %s\n", s); int isprint(int c); /* checks for any printable character including space */
int isgraph(int c); /* checks for any printable character except space */
return 0;
}

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.109 195 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.120 206

Chapter 8 — C Characters and Strings String Conversion Functions from stdlib.h


• Character handling No error detection:
• String handling int atoi(const char *nptr );
long atol(const char *nptr );
• Accessing memory chunks long long atoll(const char *nptr );
Chapter 9 — C Formatted Input/Output double atof (const char *nptr );

• printf and scanf Setting endptr to first invalid character, and setting errno:
long int strtol(const char *nptr , char **endptr , int base);
long long int strtoll(const char *nptr , char **endptr , int base);
unsigned long int strtoul(const char *nptr , char **endptr , int base);
unsigned long long int strtoull(const char *nptr , char **endptr , int base);

double strtod(const char *nptr , char **endptr );


float strtof (const char *nptr , char **endptr );
long double strtold(const char *nptr , char **endptr );
SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.121 207 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.131 217

Using strtod String Manipulation Functions (string.h)


#include <stdio.h> size_t strlen(const char *s);
#include <stdlib.h>
#include <errno.h> char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
int main( int argc, char * argv[] )
{
double d; /* variable to hold converted number */ char *strcat(char *dest, const char *src);
char *restPtr ; /* pointer variable to hold rest pointer */ char *strncat(char *dest, const char *src, size_t n);

errno = 0;
int strcmp(const char *s1, const char *s2);
d = strtod( argv[1], &restPtr );
int strncmp(const char *s1, const char *s2, size_t n);
if (errno) perror ("ERROR in strtod");
printf ( "Conversion of the string \"%s\"\n", argv[1] ); int strcasecmp(const char *s1, const char *s2);
printf ( " * produces the double value “%.2g”\n", d); int strncasecmp(const char *s1, const char *s2, size_t n);
printf ( " * and leaves the remainder string \"%s\"\n", restPtr );
int strcoll(const char *s1, const char *s2); /* uses locale */
return 0;
}

SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.126 212 SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.132 218

Standard Input/Output (stdio.h) String Search Functions (string.h)


int getchar (void); /* returns character or EOF */ char *strchr (const char *s, int c);
char *gets(char *s); /* reads up to newline or EOF */ char *strrchr (const char *s, int c);

int putchar (int c); /* returns c , or EOF on error */ size_t strspn(const char *s, const char *accept);
int puts(const char *s); /* returns EOF on error */ size_t strcspn(const char *s, const char *reject);

int sprintf ( char *str , const char *format, ...); char *strpbrk(const char *s, const char *accept);
int snprintf (char *str , size_t size, const char *format, ...);
char *strstr (const char *haystack, const char *needle);
From the man page: The function snprintf does not write more than size bytes
(including the trailing ’\0’). If the output was truncated due to this limit then the char *strtok( char *s, const char *delim); /* Don’t use! */
return value is the number of characters (not including the trailing ’\0’) which char *strtok_r(char *s, const char *delim, char **ptrptr ); /* Don’t use! */
would have been written to the final string if enough space had been available.
SE2S03, 2006 — WOLFRAM KAHL, Computing and Software, McMaster University 3.133 219

Memory Functions (string.h)


void *memcpy(void *dest, const void *src, size_t n);
/* ranges must not overlap */

void *memmove(void *dest, const void *src, size_t n);


/* handles overlapping ranges */

int memcmp(const void *s1, const void *s2, size_t n);

void *memchr (const void *s, int c, size_t n);


void *memrchr (const void *s, int c, size_t n); /* GNU extension */

void *memset(void *s, int c, size_t n);

You might also like