代写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:
#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
#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.
#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:
#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:
#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.
#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
:
// 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