C代写:CS240 Introduction to Points

代写C语言中的指针相关作业,涉及到指针和地址使用的方方面面,工作量略大。

Step 0. Introduction

In this lab you will implement memdump to display memory content, introduction to pointers, and implement string functions with pointer.

Type the following commands:

cd
cd cs240
tar -xvf  /homes/cs240/lab5-ptr-memdump/lab5-src.tar

Step 1. Checking the Endianess

Integers can be represented in memory in two ways: Little-Endian or Big-Endian. In Little-Endian, the least significant byte of the integer is stored the lowest address in memory. In Big-Endian, the least significant byte is stored in the highest address in memory.

cd cs240/lab5-src

Using your favorite editor create a new file called endian.c

Then copy the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
int isLittleEndian() {
int a = 0x05;
char * p = (char *) &a;
if (*p==0x05) {
return 1;
}
return 0;
}

int main()
{

if (isLittleEndian()) {
printf("Machine is Little Endian\n");
}
else {
printf("Machine is Big Endian\n");
}
}

This function “isLittleEndian()” defines a variable “a” and assigns the number 5 to it. Then it defines a pointer “p” of type (char *) and assigns the address of “a” to “p”. The operand “&” obtains the address of the variable you place on the right side. A pointer is just an address in memory. In this way, p points to the first byte of the variable “a” and “*p” gives the contents of the first byte of “a”. If the first byte of “a”, dereferenced as “*p”, happens to contain the value 5, then it means that the byte in the lowest address of “a” is the least significant or Little Endian. Otherwise, it means that the byte in the lowest address is the most significant or Big Endian.

Then save the program. Then compile it and run it:

gcc -o endian endian.c
./endian

Step 2. Memory Sections

The memory of the program is divided in the following memory sections:

Memory Section Name Description Access
text (or code segment) This is the area of memory that contains the machine instructions that corresponds to the compiled program. This area is shared by multiple instances of a running program. The text segment also contains constants such as string literals and variables defined using the const keyword. Read, Execute
data This area in the memory image of a running program contains storage for initialized global variables, and static variables that are explicitly initialized to a non-zero value. This area is separate for each running instance of a program. Read, Write
bss This is the memory area that contains storage for uninitialized global variables and static variables that are not explicitly initialized or initialized to zero. It is also separate for each running instance of a program. Read, Write
stack This region of the memory image of a running program contains storage for the automatic (non-static local) variables of the program. It also stores context-specific information before a function call, e.g. the value of the Instruction Pointer (Program Counter) register before a function call is made. On most architecture the stack grows from higher memory to lower memory addresses. A running instance of a program can have multiple stacks (as in a multithreaded program) Read, Write
heap This memory region is reserved for dynamically allocating memory for variables, at run time. Dynamic memory allocation is done by using the malloc or calloc functions and new operator. Read, Write
shared libraries This region contains the executable image of shared libraries being used by the program. Read, Execute

Open a file lab5-src/sections.c and copy the following program:

cd cs240/lab5-src
vim sections.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <stdlib.h>

int a=5;

int buffer[1000000];

int foo() {
int d;
static int e = 5;

printf("&d=%p &le=%p\n", &d, &e);
}

int main()
{

int b;
static int c;
int * p = (int *) malloc(sizeof(int));
char * str = "Hello World\n";

printf("&a=%p\n", &a);
printf("&b=%p &c=%p\n", &b, &c);
printf("&p=%p p=%p\n", &p, p);
printf("&str=%p str=%p\n", &str, str);
foo();

printf("main=%p &foo=%p\n", main, &foo);
}

Then save the program, compile it and run it.

gcc -o sections sections.c
./sections

Create a table like the following one, but with all the variables and sections listed. Make sure that the memory addresses are in ascending order. Print the table and turn it in in next lab.

Address     Variable/Function   Section
----------- -----------------   -------
0x4005bc    foo                 Text
0x4005e1    main                Text

You will turnin lab5-src/memory.txt together with the other files.

Step 3. Memory Dump

Open the file lab5-src/mymemdump.c by

cd cs240/lab5-src
vim mymemdump.c

Read and complete the function mymemdump(char *p, int len) that dumps in hexadecimal byte by byte the memory starting at “p” len bytes. An example output is given at the end of the program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void mymemdump(FILE * fd, char * p , int len) {
// Add your code here.
// You may see p as an array.
// p[0] will return the element 0
// p[1] will return the element 1 and so on

fprintf(fd, "0x%016lX: ", (unsigned long) p);
int c = p[0]&0xFF;

// Print first byte as hexadecimal
fprintf(fd, "%02X ", c);

// Print first byte as character
fprintf(fd, "%c", (c>=32&&c<127)?c:'.');
fprintf(fd,"\n");
}

Type “make” in lab5-src. The file mymemdump.c is linked together with mem.c to form the executable mem. Here is an example of the output. For every line, print the address, each byte in hexadecimal, and then, in the right column, the ascii value. The ascii value will be printed only if the ascii value is visible 32<=c<=127, otherwise, it will print a ‘.’.

cs240@data ~/lab5/lab5-src $ ./mem
&x=0x7FFF89A62890
&y=0x7FFF89A628A8
0x00007FFF89A62890: 41 33 40 50 09 00 00 00 30 06 9C 50 D7 7F 00 00  [email protected]..
0x00007FFF89A628A0: 94 28 A6 89 FF 7F 00 00 00 00 00 00 00 00 28 40  (........(@
0x00007FFF89A628B0: 48 65 6C 6C 6F 20 77 6F 72 6C 64 0A 00 00 00 00  Hello world.....
0x00007FFF89A628C0: FF B2 F0 00 00 00 00 00 00 00 00 00 00 00 00 00  .............
head=0x1e83010
0x0000000001E83010: 30 30 E8 01 00 00 00 00 50 30 E8 01 00 00 00 00  00.....P0.....
0x0000000001E83020: 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00  ........!.......
0x0000000001E83030: 57 65 6C 63 6F 6D 65 20 00 00 00 00 00 00 00 00  Welcome ........
0x0000000001E83040: 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00  ........!.......
0x0000000001E83050: 70 30 E8 01 00 00 00 00 90 30 E8 01 00 00 00 00  p0.....0.....
0x0000000001E83060: 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00  ........!.......
0x0000000001E83070: 74 6F 20 00 00 00 00 00 00 00 00 00 00 00 00 00  to .............
0x0000000001E83080: 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00  ........!.......
cs240@data ~/lab5/lab5-src $

Run your version of memdump that prints the output above. The output may be different than the output above because the addresses will be different. However, the content will be the same. Copy the output into a MSWORD, RTF, or HTML file lab5-src/mem.doc and then with different colors indicate where the following items are located in the output and their value. Also add the following table with the right values. Color each entry in the table with the corresponding color.

Variable            Address of Variable     Value of Variable
------------------- ---------------------   ----------------- 
str
a
b
y
x.a
x.i
x.b
x.p
head
head->str
head->next
head->next->str
head->next->next
head->next->next->str
head->next->next->next

Note: Some of the variables are pointers. The Value of pointer is the address it stores.

Hint: The file lab5-src/hintdump.c includes the barebones of the memdump function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void mymemdump(FILE * fd, char * p , int len) {
int i;
fprintf(fd, "0x%016lX: ", (unsigned long) p);
// Print address of the beginning of p. You need to print
// it every 16 bytes

for (i=0; i < len; i++) {
int c = p[i]&0xFF; // Get value at [p]. The &0xFF is to make
// sure you truncate to 8bits or one byte.

// Print first byte as hexadecimal
fprintf(fd, "%02X ", c);

// Print first byte as character. Only print
// characters >= 32 that are the printable characters.
fprintf(fd, "%c ", (c>=32)?c:'.');

if (i % 16 == 0 ) {
fprintf(fd,"\n");
}
}
}

int main() {
char a[30];
int x;
x = 5;
strcpy(a,"Hello world\n");
mymemdump(stdout,(char*) &x, 64);
}

Step 4. Implement String Functions Using Pointers

In the file mystring.c implement the string functions indicated using pointers. Do not use predefined string functions such as strlen, strcpy etc. You have to write your own. Also, do not use the array operator [ ] and use pointers instead. Run the testall script to verify that your implementation is correct.

mystring.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdlib.h>
#include "mystring.h"

int mystrlen(char * s) {
return 0;
}

char * mystrcpy(char * dest, char * src) {
return NULL;
}

char * mystrcat(char * dest, char * src) {
return NULL;
}

int mystrcmp(char * s1, char * s2) {
return -1;
}

char * mystrstr(char * hay, char * needle) {
return NULL;
}

char * mystrdup(char * s) {
return NULL;
}

char * mymemcpy(char * dest, char * src, int n)
{

return NULL;
}

Step 5. Implementing Array Functions

Implement the array operations indicated in the file array.c Do not use “[ ]” and instead use pointers. Run the testall script to verify that they are correct.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include "array.h"

// Return sum of the array
double sumArray(int n, double * array) {
double sum = 0;
double * p = array;
double * pend = p+n;

while (p < pend) {
sum += *p;
p++;
}

return sum;
}

// Return maximum element of array
double maxArray(int n, double * array) {
return 0;
}

// Return minimum element of array
double minArray(int n, double * array) {
return 0;
}

// Find the position int he array of the first element x
// such that min<=x<=max or -1 if no element was found
int findArray(int n, double * array, double min, double max) {
return -1;
}

// Sort array without using [] operator. Use pointers
// Hint: Use a pointer to the current and another to the next element
int sortArray(int n, double * array) {
}

// Print array
void printArray(int n, double * array) {
}

Step 6: File Dump

Using your implementation of MemoryDump in Step 3 write a program:

myfiledump file [maxbytes]

That prints a byte dump similar to MemoryDump but using a file insteqad of memory.

Where “file” is the name of the file to print. The parameter “maxbytes” is optional and indicates the number of bytes to print. If “maxbytes” does not exist, then it will print the entire file.

Write your implementation in the file myfiledump.c.

We give you the file ./myfiledump.org that is our solution to this program so you can compare with.

For example:

cs240@data ~/lab5-ptr-memdump/lab5-src $ ./myfiledump.org mem.c
0x0000000000000000: 0A 23 69 6E 63 6C 75 64 65 20 3C 73 74 64 69 6F  .#include <stdio
0x0000000000000010: 2E 68 3E 0A 23 69 6E 63 6C 75 64 65 20 3C 73 74  .h>.#include <st
0x0000000000000020: 72 69 6E 67 2E 68 3E 0A 23 69 6E 63 6C 75 64 65  ring.h>.#include
0x0000000000000030: 20 3C 73 74 64 6C 69 62 2E 68 3E 0A 0A 76 6F 69   <stdlib.h>..voi
0x0000000000000040: 64 20 6D 79 6D 65 6D 64 75 6D 70 28 46 49 4C 45  d mymemdump(FILE
0x0000000000000050: 20 2A 66 64 2C 20 63 68 61 72 20 2A 20 70 20 2C   *fd, char * p ,
0x0000000000000060: 20 69 6E 74 20 6C 65 6E 29 3B 0A 0A 73 74 72 75   int len);..stru

Or

cs240@data ~/lab5-ptr-memdump/lab5-src $ ./myfiledump.org myfiledump.org 100
0x0000000000000000: 7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00  .ELF............
0x0000000000000010: 02 00 3E 00 01 00 00 00 E0 06 40 00 00 00 00 00  ..>.......@.....
0x0000000000000020: 40 00 00 00 00 00 00 00 88 23 00 00 00 00 00 00  @........#......
0x0000000000000030: 00 00 00 00 40 00 38 00 0A 00 40 00 22 00 1F 00  [email protected]...@."...
0x0000000000000040: 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00  ........@.......
0x0000000000000050: 40 00 40 00 00 00 00 00 40 00 40 00 00 00 00 00  @.@.....@.@.....
0x0000000000000060: 30 02 00 00                                      0...

Hints:
Use FILE * fin = fopen(...) to open the file passes as argument. See “man fopen”
You can determine the length of the file by using the following sequence. Fine :

1
2
3
4
// Get file size
fseek(fin, 0L, SEEK_END); // Go to the end of the file fin
int fileSize = ftell(fin); // Get current file pointer
fseek(fin, 0L, SEEK_SET); // Go back to the beginning of the file.

Allocate a large chunk of size fileSize bytes using malloc and read the whole file into it using fread.
Copy your implementation of memoryDump into myfiledump.c and modify to print using offset 0 as the beginning.

Step 7. Determine the Signature of Special Files

The first few bytes of an executable are called “The Magic Number” or “Signature
and are used by different programs to identify the type of a file. Using your myfiledump tool find the signature for the following files as well as the extension used. Sometimes the signature shows later in the file at some known “Offset” but most of the time appears at the beginning (

File Type Extension Signature Signature Offset
Executable file
WAV file
JPEG
GIF
TAR
ZIP

Write this table in a file signature.txt and include it in lab5-src/signature.txt

Step 8. Our Tests

Also, make sure that your program passes our tests. To run the tests, compile your program and type

./testall

or run each individual test as indicated in the output.
Make sure that all tests pass and testall gives the maximum points.

Step 9. Turning In your Project

Follow these instructions to turnin lab5:

cd cs240
turnin -c cs240 -v -p lab5 lab5-src