Sams Teach Yourself C in 24 Hours (46 page)

BOOK: Sams Teach Yourself C in 24 Hours
5.52Mb size Format: txt, pdf, ePub

The statement in line 9 gives the declaration of a pointer (ptr) to the StrPrint() function: that is, int (*ptr)(char *str);.

Note that the pointer, ptr, is specified with the int data type and passed with a char pointer. In other words, the format of the pointer declaration in line 9 is quite similar to the declaration of StrPrint() in line 4. Please remember that you have to put the *ptr expression between a pair of parentheses (( and )) so that the compiler won’t confuse it with a function name.

In line 11, the left value (that is, the address) of the StrPrint() function is assigned to the ptr pointer. Then, the (*ptr)(str) expression in line 12 calls the StrPrint() function via the dereferenced pointer ptr, and passes the address of the string declared in line 8 to the function.

From the definition of the StrPrint() function in lines 18–22, you can tell that the function prints out the content of a string whose address is passed to the function as the argument. Then, 0 is returned at the end of the function.

In fact, the if statement in lines 12 and 13 checks the value returned by the StrPrint() function. When the value is 0, the printf() call in line 13 displays the string Done! on the screen.

The output of the program in Listing 16.8 shows that the StrPrint() function has been invoked successfully by using a pointer that holds the address of the function.

21 067231861x CH16 1/25/00 10:36 AM Page 276

276

Hour 16

Summary

In this lesson you’ve learned the following very important concepts and applications of pointers and arrays in C:

• You should always make sure that a pointer is pointing to a legal and valid memory location before you use it.

• The position of a pointer can be moved by adding or subtracting an integer.

• The scalar size of a pointer is determined by the size of its data type, which is specified in the pointer declaration.

• For two pointers of the same type, you can subtract one pointer value from the other to obtain the offset between them.

• The elements in an array can be accessed via a pointer that holds the start address of the array.

• You can pass an unsized array as a single argument to a function.

• Also, you can pass an array to a function through a pointer. The pointer should hold the start address of the array.

• You can either pass the unsized format of a multidimensional array, or a pointer that contains the start address of the multidimensional array, to a function.

• A function that takes an array as an argument does not know how many elements are in the array. You should also pass the number of elements as another argument to the function.

• Arrays of pointers are useful in dealing with character strings.

• You can assign a pointer to the address of a function, and then call the function using that pointer.

In the next lesson you’ll learn how to allocate memory in C.

Q&A

Q Why do you need pointer arithmetic?

A
The beauty of using pointers is that you can move pointers around to get access to valid data that are saved in those memory locations referenced by the pointers. To do so, you can perform pointer arithmetic to add (or subtract) an integer to (or from) a pointer. For example, if a character pointer, ptr_str, holds the start address of a character string, the ptr_str+1 expression moves to the next memory location, which contains the second character in the string.

21 067231861x CH16 1/25/00 10:36 AM Page 277

Applying Pointers

277

Q How does the compiler determine the scalar size of a pointer?

A
The compiler determines the scalar size of a pointer by its data type, which is specified in the declaration. When an integer is added to or subtracted from a pointer, the actual value the compiler uses is the multiplication of the integer and the size of the pointer type. For instance, given an int pointer ptr_int, the expression ptr_int + 1 is interpreted by the compiler as ptr_int + 1 * sizeof(int). If the size of the int type is 2 bytes, the ptr_int + 1 expression really means to
16

move 2 bytes higher from the memory location referenced by the ptr_int pointer.

Q How do you get access to an element in an array by using a pointer?

A
For a one-dimensional array, you can assign the start address of an array to a pointer of the same type, and then move the pointer to the memory location that contains the value of an element in which you’re interested. Then you dereference the pointer to obtain the value of the element. For multidimensional arrays, the method is similar, but you have to think about the other dimensions at the same time (See the example shown in Listing 16.6.)

Q Why do you need to use arrays of pointers?

A
In many cases, it’s helpful to use arrays of pointers. For instance, it’s convenient to use an array of pointers to point to a set of character strings so that you can access any one of the strings referenced by a corresponding pointer in the array.

Workshop

To help solidify your understanding of this hour’s lesson, you are encouraged to answer the quiz questions and finish the exercises provided in the workshop before you move to the next lesson. The answers and hints to the questions and exercises are given in Appendix B, “Answers to Quiz Questions and Exercises.”

Quiz

1. Given a char pointer, ptr_ch, an int pointer, ptr_int, and a float pointer, ptr_flt, how many bytes will be added, respectively, in the following expressions on your machine?

• ptr_ch + 4

• ptr_int + 2

• ptr_flt + 1

• ptr_ch + 12

• ptr_int + 6

• ptr_flt + 3

21 067231861x CH16 1/25/00 10:36 AM Page 278

278

Hour 16

2. If the address held by an int pointer, ptr1, is 0x100A, and the address held by another int pointer, ptr2, is 0x1006, what will you get from the subtraction of ptr1–ptr2?

3. Given that the size of the double data type is 8 bytes long, and the current address held by a double pointer variable, ptr_db, is 0x0238, what are the addresses held, respectively, by ptr_db–1 and ptr_db+5?

4. Given the following declarations and assignments:

char ch[] = {‘a’, ‘b’, ‘c’, ‘d’, ‘A’, ‘B’, ‘C’, ‘D’};

char *ptr;

ptr = &ch[1];

what do each of these expressions do?

• *(ptr + 3)

• ptr - ch

• *(ptr - 1)

• *ptr = ‘F’

Exercises

1. Given a character string, I like C!, write a program to pass the string to a function that displays the string on the screen.

2. Rewrite the program in exercise 1. This time, change the string of I like C! to I love C! by moving a pointer that is initialized with the start address of the string and updating the string with new characters. Then, pass the updated string to the function to display the content of the string on the screen.

3. Given a two-dimensional character array, str, that is initialized as char str[2][15] = { “You know what,”, “C is powerful.” };

write a program to pass the start address of str to a function that prints out the content of the character array.

4. Rewrite the program in Listing 16.7. This time, the array of pointers is initialized with the following strings:

“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, and

“Saturday”.

22 067231861x CH17 1/25/00 10:19 AM Page 279

HOUR 17

Allocating Memory

It’s just as unpleasant to get more than you bargain for as to get less.

—G. B. Shaw

So far you’ve learned how to declare and reserve a piece of memory space before it is used in your program. For instance, you have to specify the size of an array in your program (or the compiler has to figure out the size if you declare an unsized array) before you assign any data to it at runtime. In this lesson you’ll learn to allocate memory space dynamically when your program is running. The four dynamic memory allocation functions covered in this lesson are

• The malloc() function

• The calloc() function

• The realloc() function

• The free() function

22 067231861x CH17 1/25/00 10:19 AM Page 280

280

Hour 17

Allocating Memory at Runtime

There are many cases when you do not know the exact sizes of arrays used in your programs, until much later when your programs are actually being executed. You can specify the sizes of arrays in advance, but the arrays can be too small or too big if the numbers of data items you want to put into the arrays change dramatically at runtime.

Fortunately, C provides you with four dynamic memory allocation functions that you can employ to allocate or reallocate certain memory spaces while your program is running.

Also, you can release allocated memory storage as soon as you don’t need it. These four C functions, malloc(), calloc(), realloc(), and free(), are introduced in the following sections

The
malloc()
Function

You can use the malloc() function to allocate a specified size of memory space.

The syntax for the malloc() function is

AX

#include

void *malloc(size_t size);

YNTS
, Here size indicates the number of bytes of storage to allocate. The malloc() function returns a void pointer.

Note that the header file, stdlib.h, has to be included before the malloc() function can be called. Because the malloc() function itself returns a void pointer, its type is then automatically converted to the type of the pointer on the left side of an assignment operator, according to the ANSI C standard.

There are some C compilers in the market, usually old versions, which are not 100% ANSI C compliant. If you use one of those C compilers, you may get warning or error messages complaining about your declarations of malloc(), calloc(), or realloc(). For example, if you write something like this: int *ptr;

ptr = malloc ( 10 * sizeof(int) );

you may get an error message about the return type from the malloc()

function when you try to compile the code. This is because that the C compiler that you’re using may not be 100% ANSI C compliant, and it does not know how to covert the return type of malloc(). If it is the case, what you can do is to use the casting operator (int *) shown here:

int *ptr;

ptr = (int *) malloc ( 10 * sizeof(int) );

22 067231861x CH17 1/25/00 10:19 AM Page 281

Allocating Memory

281

This indicates to the compiler the type of the pointer returned by malloc(), and shuts off the complaint from the C compiler. Here, you have to make sure the type of the allocated memory, the type of the pointer, and the type of the casting operator, are all the same. Similarly, you can add a casting operator in front of the calloc() or realloc() functions when you use a non–ANSI C compiler.

Because this book focuses on the ANSI C, which is the industry standard, I don’t use casting operators in the example programs using malloc(), calloc(), or realloc(), in the book.

If the malloc() function fails to allocate a piece of memory space, it returns a null pointer. Normally, this happens when there is not enough memory. Therefore, you should
17

always check the returned pointer from malloc() before you use it.

Listing 17.1 demonstrates the use of the malloc() function.

TYPE

LISTING 17.1

Using the malloc() Function

1: /* 17L01.c: Using the malloc function */

2: #include

3: #include

4: #include

5: /* function declaration */

6: void StrCopy(char *str1, char *str2);

7: /* main() function */

8: main()

9: {

10: char str[] = “Use malloc() to allocate memory.”;

11: char *ptr_str;

12: int result;

13: /* call malloc() */

14: ptr_str = malloc( strlen(str) + 1);

15: if (ptr_str != NULL){

16: StrCopy(str, ptr_str);

17: printf(“The string pointed to by ptr_str is:\n%s\n”,

18: ptr_str);

19: result = 0;

20: }

21: else{

22: printf(“malloc() function failed.\n”);

23: result = 1;

24: }

25: return result;

continues

22 067231861x CH17 1/25/00 10:19 AM Page 282

282

Hour 17

LISTING 17.1

continued

26: }

27: /* function definition */

28: void StrCopy(char *str1, char *str2)

29: {

30: int i;

31:

32: for (i=0; str1[i]; i++)

33: str2[i] = str1[i];

34: str2[i] = ‘\0’;

35: }

The following output is shown on the screen after the executable program, 17L01.exe, in Listing 17.1 is created and executed.

The string pointed to by ptr_str is:

Other books

Fatal North by Bruce Henderson
The Zodiac Collector by Laura Diamond
Come Fly With Me by Addison Fox
Her Lycan Lover by Susan Arden
Downsizing by W. Soliman
The Color of Death by Bruce Alexander
The Breadwinner by Deborah Ellis
A Daring Proposal by Sandra S. Kerns
Devious Minds by KF Germaine