HOMEWORK 1 FAQ (Wed, Sep 12, 1120 HRS) ERRATA ------ "CORRECTED" means that the Web version has been updated to reflect the change. Problem 1 --------- Problem 2 --------- Problem 3 --------- Problem 4 --------- Q4-1) Can you tell me what the sequence number is again? A4-1) The sequence number is equal to the line number which starts at 0 for the first line. So, unsigned long line_num = 0; while (there is a line) { ... process line making sequence number in buffer equal to line number ... ++line_num; } Q4-2) Can I just cast a char pointer to set the sequence number like this: char buf[100]; int *seqnum = (int *)(&buf[0]); *seqnum = ... whatever the sequence nuber is ... A4-2) Yes, but it is even simpler because buf is the name of a memory location containing the address of the first element of buf[]: buf [ ]------ | v --------------- | | 100 byte buffer --------------- So, char buf[100]; unsigned long *seqnum = (unsigned long *)buf; *seqnum = ... whatever the sequence number is ... Q4-3) Can you give me an example of the output? A4-3) Here is some sample output (this is NOT what the assignment asked for) with annotation to the right of the '#' character: hello how r you buf: 0xbfffc564 68 65 6c 6c 6f 0 # the ascii string "hello" 0xbfffc56a 68 6f 77 0 # "how" 0xbfffc56e 72 0 # "r" 0xbfffc570 79 6f 75 0 # "you" set xyz 32 buf: 0xbfffc560 73 65 74 0 # "set" 0xbfffc564 78 79 7a 0 # "xyz" 0xbfffc568 33 32 0 # "32" See the man page for ascii(7) for representation of ASCII characters. Note that pointers are 4 bytes and all C strings end in the null character. So, in the second example, if the line number is 7 and you print out the buffer: set xyz 32 7 0xbfffc560 0xbfffc564 0xbfffc568 73 65 74 0 78 79 7a 0 33 32 0 ... This is the format called for in the assignment; The first line is just an echo of the input. The second displays the internal format; i.e., 3 character sequence number (%3d), hex representation of pointers (%p), hex representaiton of ascii characters (%c). Visually, the buffer for the last command looks like this when the character string part is printed with each character as ASCII characters (you need a wide terminal screen for this to display properly): --------------------------------------------------------- | | -------------------------------------------- | | | | | -------------------------------- | | | | | v v v ---- -|-------|-------|--------------------------------------------------------------------- | 7 | o | o | o | 0 | s | e | t | \0 | x | y | z | \0 | 3 | 2 | \0 | -------------------------------------------------------------------------------------------- \__ __/\______________ ______________/ \_____________________ _______________________________/ V V V unsigned long char *[] char [] And like this when each character is printed in hexadecimal: --------------------------------------------------------- | | -------------------------------------------- | | | | | -------------------------------- | | | | | v v v -------|-------|-------|--------------------------------------------------------------------- | 7 | o | o | o | 0 | 73 | 65 | 74 | 0 | 78 | 79 | 7a | 0 | 33 | 32 | 0 | --------------------------------------------------------------------------------------------- Q4-4) Can I use the c++ facilities like stringstreams and cout instead of fgets and printf? A4-4) Yes. Q4-5) Can I just the code from your solution to problem 3 if we say we did that? A4-5) Yes. In fact, you can use code from on-line or from previous courses so long as: o You understand what the code actually does. o The code fragment is short and doesn't require libraries that aren't part of core Unix distributions o You cite the sources when a reasonable person might think you copied the code from somewhere Q4-6) I know you briefly discussed it as I was leaving class.... Can you give me a refresher on how to put a 4 byte long into a character array? Not so unexpectedly I am only getting one byte of the address in my simple little test program represented below..... A4-6) I have numbered the lines that you sent me. 1 unsigned long *addr = new unsigned long; 2 fgets(&buf[5], 100, stdin); // fill buf[] with line 3 *addr = (unsigned long)&buf[5]; // addr = mem addr of input string 4 fprintf(stdout,"Addr = %x\n",*addr); 5 buf[0] = *addr; 6 fprintf(stdout,"%x %x\n",(unsigned int)*buf,&buf[5]); // work??? Here I give a line-by-line commentary on what you have (my comments are preceded by "++"): 1 unsigned long *addr = new unsigned long; 2 fgets(&buf[5], 100, stdin); ++ I think you are confused by what Problem 4 is asking you to do. ++ There are two buffers: a line buffer and the internal buffer. ++ What is described about 1/4 of the way down on page 2 is ++ the INTERNAL BUFFER. This means that there are these two ++ declarations: ++ ++ const int MAX_LINE_BUF = 500; // line buffer size ++ const int MAX_BUF = 100; // internal buffer ++ char linebuf[MAX_LINE_BUF]; // line buffer ++ char buf[MAX_BUF]; // internal buffer ++ ++ Then, to read a line into the line buffer: ++ ++ int n = 0; // sequence number ++ while ( fgets(linebuf, MAX_BUF, stdin) ) { // read a line ++ printf("%s\n", linebuf); // display line ++ ... ++ ++n; ++ } 3 *addr = (unsigned long)&buf[5]; 4 fprintf(stdout,"Addr = %x\n",*addr); 5 buf[0] = *addr; 6 fprintf(stdout,"%x %x\n",(unsigned int)*buf,&buf[5]); ++ Lines 3-6 don't make sense because of my earlier comment. ++ The first field in the internal buffer is the sequence number. So, ++ ++ unsigned long *p = buf; // point to internal buffer ++ *p = n; // where n is the sequence number ++ Q4-7) What is the best way to proceed with this problem if I am unsure about a lot of the assignment? A4-7) o Sketch out the basic structure (outline) of the program. o Determine what functions you will need. o Plan out your development sequence. o Ask questions to clarify either requirements or implementation approaches. o Think of several test cases. o Code up the control structure first and put in printf or cout calls at key places to monitor the progress of your code. o Add in code blocks according to your planned development sequence. o Refactor your code as you learn more about the solution. I would think one of the first milestones is to be able to print out the command lines as they appear on the input and then print out the individual words (perhaps 1 per line and indented). Handling the hexadecimal output format would be one the last things to do since leaving it in verbose mode would be ok until you get around to dealing with command line args. But of course, if you have done this before, then it is an easy thing to do. So, here is a possible features milestone sequence (assuming you are really naive): o For all steps below, repeat previous steps if necessary and make sure that you get hard evidence that your program really provides the feature (i.e., display results). o Display "hello". o Read and display lines from stdin (i.e., echo back) until EOF o Parse each line into words (i.e., those things between whitespaces) o Display char array in hexadecimal format. o Handle the general input requirements (i.e., add in integer string capability) Q4-8) Problem 4 says that we should terminate the program if quit is the first word or end-of-file is reached. If we are getting commands from the terminal stdin, how will we get an end-of-file condition? Thank you. A4-8) If a user enters ctrl-d (hold down control key and press d key), the terminal drive sends what amounts to an eof condition to the library function that is processing stdin input. If you redirect stdin from a file, the eof condition will be raised when you attempt to read past the end of the file. Q4-9) I don't understand how you can access the char buf[100] using int *ip or unsigned long *p like in your examples. How do you put stuff in the character buffer if your using a integer pointer? Are we supposed to store the actual words in the buffer and just print out the hex values or are we storing the hex values in the buffer? A4-9) Consider this code: 1 char buf[100]; 2 int *ip; 3 ip = (int *) buf; // ip = (int *) (&buf[0]) works too 4 *ip = 3; Line 1 declares and allocates a 100 character (byte) area of memory. Line 2 declares a pointer to an integer but leaves its value uninitialized; Line 3 sets the contents of ip (an int ptr) to the memory location (address) of the beginning of the buf array. Visually: ---- ip | o-|-------- ---- | v ------------ buf --->| | | | | ... ------------ [0][1][2] ... Line 3 says more. The cast "(int *)" says "I know that buf is an array of chars, but I will be treating the first 4 bytes as containing an int when I use the variable ip." Line 4 says put the value of 3 into the location pointed at by ip AND do that by treating the destination as an int (since ip is an int ptr).