Pointers about pointers Announcements � Midterm next week � pointer is a memory address � Material covered up until June 18 (last week, � is 4 bytes like an unsigned int signals) � can address up to 2^32 bytes = 4 gb � Allowed to have 1 cheat sheet � declaring a pointer allocates 4 bytes for the � No tutorial pointer itself - that's it! � Come to class at 6 char * ptr; � Test is 6:10 – 7:00 gets(ptr); � Assignment 3 is on the web site � will compile, but crash Pointer type Example char * pchar; int * pint; � pointers are typed struct mystruct * pstruct; int arry[3][3] = { {1,2,3}, � char * pchar; vs. int * pint, {4,5,6}, struct mystruct * pstruct; {7,8,9}}; � similarity: all are 4 bytes pchar = (char *)arry; pint=(int *)arry; � difference: pstruct=(struct mystruct *)arry; printf("pchar=%p,pint=%p,pstruct=%p\n",pchar,pint,pstruct); � pchar++; //increment by 1 byte pchar+=1; pint+=1; pstruct+=1; printf("pchar=%p,pint=%p,pstruct=%p\n",pchar,pint,pstruct); � pint++; //increment by 4 bytes pchar=0012FF50,pint=0012FF50,pstruct=0012FF50 � pstruct++; //increment by sizeof(mystruct) pchar=0012FF51,pint=0012FF54,pstruct=0012FF58 1
Multi-dimensional arrays Arrays � The name of an array is the memory address of the � int twodbuf [3][3]; array � allocates contiguous chunk of memory that is � It is a const pointer - cannot do arithmetic on it: 3x3xsizeof(int)=36 bytes char buf[100]; � twodbuf is of type int ** buf=buf+1; //illegal! � but you can do this: � In other words: twdbuf is an array of int * � so twodbuf[i] is of type int * char * ptr; � (twodbuf[i])[j] is of type int ptr=buf; ptr+= 50; //points half way through this array. Example: Truth about multi-dimensional arrays arry == 0x12ff50 � No such thing. 0012FF50 01 00 00 00 02 00 00 00 03 00 00 00 ............ 0012FF5C 04 00 00 00 05 00 00 00 06 00 00 00 ............ � A 2d array is just made up of a bunch of 1D 0012FF68 07 00 00 00 08 00 00 00 09 00 00 00 ............ arrays 0012FF74 CC CC CC CC 50 FF 12 00 50 FF 12 00 ÌÌÌÌPÿ..Pÿ.. � There are only really ever 1D arrays 2
parameter passing Dynamic allocation (2D arrays) allocate 2d array of dimension: row,col of chars � When you pass an array, you really just pass the pointer: easyway (works only is col is same for every row): char * ptr=new char [row*col];//or ptr=(char*)malloc(row*col*sizeof(char)); void myfunc(char * arry) is the same as //index the i,j element: void myfunc(char arry[]) char * pij = ptr + i*col + j; � pointers are passed by value! //harder, more general way. works even if col is not the same for every row. Consider: char ** ptr; void assignptr(char * dst,char * src) ptr = new char * [row]; // or ptr=(char ** ) malloc(row*sizeof(char *)); for(i=0;i<row;i++) { { ptr[i]= new char[col]; // or ptr[i]= (char ) malloc(col*sizeof(char)); dst=src; } } //index i,j element: ptr[i][j] char arry[10],* ptr; assignptr(ptr,arry);//does nothing. //how to fix?? Make files Dependency tracking � Why Makefiles? � Need to know: if I change a file, which other file(s) need to be updated too? � Up until now, we've built projects using shell scripts � Complete rebuild everytime something changes � Example: change a #define in a .h file, then � Ok for small projects all files that include the .h need to be � But for large projects (10s of thousands of files, recompiled millions of lines of code) a rebuild is NOT ok � Makefiles and the make utility allows you to � Build ONLY what's needed (incremental build) do this 3
make General format of a makefile � The make utility updates a bunch of files � The general format is: according to dependency stored in a "makefile" target: depdency1,dependency2... � make -f mymakefile <tab> <how to create target based on dependencies> � or just � make dependency1: <more dependencies> � If no file specified, automatically look for <tab><how to create dependency1> "makefile" ... Example Dependency tree of the above main1: main1.o reverse.o g++ -omain1 main1.o reverse.o main1.o: main1.cpp reverse.h g++ -c main1.cpp reverse.o: reverse.cpp reverse.h g++ -c reverse.cpp 4
touch clean � make works by looking at time stamps � The above rules leave a lot of .o files around � if any dependencies have a newer time � Usually, there is a "clean" rule: stamp, the target needs to be rebuilt clean: � Traces dependencies up the tree rm -f *.o � If after a full build you say "make", then � removes all the intermediate files nothing happends � but any build after this will be a full build � use touch to update the time stamp Inter-Process Communication (IPC) Inter-process Communication � Data exchange techniques between processes: � message passing: files, pipes, sockets � shared-memory model � Limitations of files for IPC � slow, others can modify files � Limitations of pipes � two processes must be related and running on the same Pipes (Haviland – Ch. 7) machine. � Limitations of sockets � full network protocol stack required from PF_INET (necessary if the processes are on different machines) � PF_LOCAL similar to pipes – better performance than PF_INET between processes on the same machine 5
Producer/Consumer Problem Producer/Consumer � Simple example: who | wc –l � consumer should be blocked when buffer is empty � producer should be blocked when buffer is full � Both the writing process ( who ) and the � producer and consumer should run independently reading process ( wc ) of a pipeline execute as far as buffer capacity and contents permit concurrently. � producer and consumer should never be updating � A pipe is usually implemented as an internal the buffer at the same instant (otherwise data OS buffer. integrity cannot be guaranteed) � It is a resource that is concurrently accessed � producer/consumer is a harder problem if there are by the reader and the writer, so it must be more than one consumer and/or more than one producer. managed carefully. File Descriptors Revisited pipe() � Used by low-level I/O � Create pipe with: � open(), close(), read(), write() int pipe(int filedes[2]) � declared as an integer � filedes is a 2 integer array that holds the file � int fd; descriptors for each end of the pipe � Not the same as a “file stream”: FILE *fp; � filedes[0] is open for reading � A useful system call to convert a stream to a fd � filedes[1] is open for writing int fileno( FILE *fp); � The pipe is just an internal OS buffer � Of course it is possible to assign a stream interface to a file descriptor � Data treated in FIFO (first in, first out) basis FILE *fdopen(int fd, const char *mode); � lseek() will not work on pipes 6
Simple example: int pipe(int filedes[2]) ...other declarations... user process int p[2]; � half-duplex if(pipe(p)==-1) { (one-way) ...print error, quit... fd[0] fd[1] communication } write(p[1],msg1,MSGSIZE); write(p[1],msg2,MSGSIZE); read write //read it back for(j=0;j<2;j++) { read(p[0],inbuf,MSGSIZE); pipe printf("%s\n",inbuf); } ...rest of program kernel Pipes only useful with fork() What happens after fork? � Recall file descriptors remain open across a fork() call user process user process int p[2]; if(pipe(p)==-1) { ...print error, quit... } fd[0] fd[1] fd[0] fd[1] if(!fork()) { write(p[1],msg1,MSGSIZE); write(p[1],msg2,MSGSIZE); } else { //read it back for(j=0;j<2;j++) { read(p[0],inbuf,MSGSIZE); pipe printf("%s\n",inbuf); } } kernel ...rest of program 7
Direction of data flow? Pipes and File Descriptors parent child � A forked child inherits file descriptors from its parent � pipe() creates an internal system buffer and fd[0] fd[1] fd[0] fd[1] two file descriptors, one for reading and one for writing. � After the pipe call, the parent and child should close the file descriptors for the pipe child to parent parent to child opposite direction. Leaving them open does close fd[1] in parent (close fd[0] in parent not permit full-duplex communication. and fd[0] in child) and fd[1] in child) kernel Correct code dup2() int p[2]; if(pipe(p)==-1) { � Often we want the stdout of one process to ...print error, quit... } be connected to the stdin of another process. if(!fork()) { close(p[0]); � Point one FD to the location pointed to by the write(p[1],msg1,MSGSIZE); write(p[1],msg2,MSGSIZE); other FD } else { returnCode = dup2( oldFD, newFD ); close(p[1]); //read it back � newFD and oldFD now refer to the same file for(j=0;j<2;j++) { read(p[0],inbuf,MSGSIZE); � if newFD is open, it is first automatically closed printf("%s\n",inbuf); � Note that dup2() refer to fds not streams } } ...rest of program 8
Recommend
More recommend