Key C Topics: Tutorial Pointers, Dynamic Memory …cs370/Spring18/lectures/Help...Outline •...

Post on 26-Mar-2018

221 views 4 download

Transcript of Key C Topics: Tutorial Pointers, Dynamic Memory …cs370/Spring18/lectures/Help...Outline •...

Key C Topics: Tutorial

Pointers, Dynamic Memory

allocation, Valgrind and

Makefile

CS370

Outline

• Pointers in C• & and * operators• Pointers with Arrays and Strings

• Dynamic memory allocation• malloc() and free()• Valgrind tool

• Makefile

What is a Pointer?

• int k; k =2;• ‘k’ is the name given to the memory location which

stores the value 2. As the data type used is int, 4 bytes of memory is reserved for k.

• Internally the memory is identified by an address, which is what ’k’ refers to. This address of ‘k can be accessed by using the & operator, i.e. &k

• int *p = &k;• Here ‘p’ is a pointer variable, hence the

dereferencing (*) operator before it. The pointer variable ’p’ holds the address where the ’k’ holds the value.

• Hence *p = 2 is equivalent to k = 2

What is a Pointer?

Data Type of a Pointer

• *(p+1) = ?

C increments the pointer based on the type of variable it points to. In the above case as it points to int, ‘p’ is incremented by 4, so we have (p+1)=0x100 and *(p+1)=7

Pointers and Arrays

p = &arr[0];

The symbol arr itself is a pointer to the first

element of the array.

• Hence, arr[i] can also be written as *(arr+i)

Pointers and Arrays

int arr[3]= 1,2,3; int *p = arr;p is pointing to arr[0](=1);

Step1: printf(“%d”,*p++)

Get value at p: 1 (output)

Increment p: p is now pointing to arr[1]

Step2: printf(“%d”,*++p)Increment p: p is now pointing to arr[2]

Get value at p: 3 (output)

Step3: printf(“%d”,++*p)Increment value at p and then print it• arr[2]=3+1=4(output)

Pointers and Strings

A string in C is simply an array of char values

So the functioning of pointers with strings is

same as that with the arrays.

char strA[] = “Ping”;char strB[] = “Pong”;char *pA = strA;

char *pB = strB;

while (*pA) *pB++ = *pA++;*pB = '\0’;;

Pointers and Strings

• Put the reverse of str1 into str2:

char str1[] = "Pointers are fun. Yeah right!";char str2[30], *p1, *p2;

p1 = str1 + strlen(str1) - 1;p2 = str2;

while(p1 >= str1) *p2++ = *p1--;*p2 = '\0';

Pointers and Multi-Dimensional Arrays

arr[2] is the pointer to the third row

So, we can access arr[2][1] as *(arr[2]+1)

But arr[2] is again same as *(arr + 2)

So, arr[2][1] is same as *(*(arr+2)+1)

In general, arr[i][j] is same as *(*(arr+i)+j)

Dynamic Memory Allocation

int arr[1000];- sets aside 1000*sizeof(int) bytes of memory irrespective of whether you use it or not

Instead, use malloc() to allocate memory atruntime depending on requirement

And then when you are done using it, use

free() to deallocate itmalloc’ed memory will not be automaticallyfreed until process exits

malloc()

int *p = (int *)malloc(sizeof(int)*N)--

-

-

allocates enough memory to hold N int values

returns the starting address of the memory block

we store the address in the pointer pmalloc() returns NULL if memory could not be

allocatedWe can use *p, *(p+1), ..., *(p+N-1) to refer to

the integers in the memory block

But, *(p+i) is same as p[i]

Effectively, we just dynamically allocated an arrayto hold N integers

free()

• free(p)

-

-

deallocates the memory addressed by p

It’s good practice to set the pointer to NULL: p=NULL

Dynamic Memory for 2D Arrays

•Recall that each row of a 2D array can bereferenced by a pointer to a 1D array• So for 2D arrays, we need a 1D array of pointers

int **p;

p = (int **) malloc(Nrow * sizeof(int *))We just allocated memory to hold Nrow pointers,•

accessed as *(p+i) (or p[i])

for (i=0; i<Nrow; i++)p[i] = (int *)malloc(Ncol * sizeof(int))

•Each of those pointers now points to a block ofmemory of size (Ncol*sizeof(int))

Dynamic Memory for 2D Arrays

To access the integer at row I and column j, use- *(*(p+i)+j) or p[i][j]

Each *(p+i) need not point to a memory block of samesize

- therefore, each column of the array can be of differentsize

Tofree the memory:for (i=0; i<Nrow; i++) free(p[i]);

free(**p); p=NULL;

You may also free only certain columns:

free(p[2]); p[2]=NULL;

malloc() example

#include <stdio.h>

#include <stdlib.h>

int main()

int n, i, *ptr, sum=0;

prinm("Enter number of elements: ");

scanf("%d",&n);

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

if(ptr==NULL)

// number of elements entered by user

//memory allocated using malloc

prinm("Error! memory not allocated.");

exit(0);

prinm("Enter elements of array: ");

for(i=0;i<n;++i) //

//

array values entered by userscanf("%d",ptr+i);

sum+=*(ptr+i);

prinm("Sum=%d",sum);

free(ptr); don’t forgetfree()!

return 0;

Valgrind• Valgrind is a program that is useful for tracking

memory errors (such as segmentation faults) and memory leaks.

• If working on your own machine you may have to install valgrind using: sudo apt install valgrind

• You may run Valgrind with any of your C programs with the following:

valgrind --leak-check=yes ./<executable name>

• If you want to see the line numbers where memory was allocated you must compile with the –g flag.

Ex. gcc –o test –g test.c

Valgrind ExampleBelow is a simple C program to demonstrate valgrind. I ran the program twice with valgrind and included the valgrind output in later slides.

// header files#include <stdio.h>#include <stdlib.h>// main functionsint main()

// give memory leak example// allocate an array of 10 integersint *numPtr = malloc(sizeof(int)*10);int temp = numPtr[1]; // access one value in the arrayfree(numPtr); // free memoryreturn 0;

Valgrind Example Cont.Below are the results of running valgrind with the program when memory is properly freed and accessed. ==3447== Memcheck, a memory error detector==3447== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.==3447== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info==3447== Command: ./valTest==3447== ==3447== ==3447== HEAP SUMMARY:==3447== in use at exit: 0 bytes in 0 blocks ==3447== total heap usage: 1 allocs, 1 frees, 40 bytes allocated==3447== ==3447== All heap blocks were freed -- no leaks are possible==3447== ==3447== For counts of detected and suppressed errors, rerun with: -v==3447== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Notice there is no memory in use at exit

Notice the number of allocsis equal to number of frees

Valgrind Example Cont.Below are the results of running valgrind when memory is not freed and is accessed out of bounds. I removed some unnecessary output from valgrind to save space.

==3518== Invalid read of size 4==3518== at 0x108664: main (valTest.c:11)==3518== Address 0x521c1d0 is 288 bytes inside an unallocated block of size 4,194,096 in arena "client"==3518== ==3518== ==3518== HEAP SUMMARY:==3518== in use at exit: 40 bytes in 1 blocks==3518== total heap usage: 1 allocs, 0 frees, 40 bytes allocated==3518== ==3518== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1==3518== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)==3518== by 0x10865B: main (valTest.c:10)

Accessing an array out of bounds – line 11

Notice there is still memory in use at exit and the number of allocs does not equal number of frees

There was a memory leak of 40 bytes in one block. Allocated on line 10.

Valgrind Example Cont.Below is a continuation of the last slide. Valgrind provides a summary of memory leaks.

==3518== LEAK SUMMARY:==3518== definitely lost: 40 bytes in 1 blocks==3518== indirectly lost: 0 bytes in 0 blocks==3518== possibly lost: 0 bytes in 0 blocks==3518== still reachable: 0 bytes in 0 blocks==3518== suppressed: 0 bytes in 0 blocks

Makefile basics

• A makefile is simply a way of associating short

names, called targets, with a series of

commands to execute when the action is

requested

-

-

Default target: make

Alternate target: make clean

Makefile

••

Basic macro: CC=gcc

Convert a macro to its value in a target: $(CC)- Ex: $(CC) a_source_file.c gets expanded to gcca_source_file.c

• Basic makefile:CC = gcc

FILES = in_one.c in_two.cOUT_EXE = out_executablebuild: $(FILES)

$(CC) -o $(OUT_EXE) $(FILES)

• To execute: make build

Make clean

CC = gccFILES = in_one.c in_two.c

OUT_EXE = out_executablebuild: $(FILES)

$(CC) -o $(OUT_EXE) $(FILES)

clean:rm -f *.o $(OUT_EXE)

•The target make clean will remove all .o filesand the executable

References

A Tutorial on Pointers And Arrays in C:

http://home.netcom.com/~tjensen/ptr/pointers.htm

Essential C:

http://cslibrary.stanford.edu/101/EssentialC.pdf

Reading C Type Declarations:

http://unixwiz.net/techtips/reading-cdecl.html

C Programming Dynamic Memory Allocation

http://www.programiz.com/c-programming/c-dynamic-memory-

allocation

• Makefiles

http://www.cprogramming.com/tutorial/makefiles.html