My assignment is to mimic the Unix tail command. For those of you who do not know it, it prints out the last n lines of a file. I think I am going to have a lot of questions.
We can't use std::vector<std::strings>, we must use char**
So the char** is allocated to hold n lines, and then each char* in the array is allocated to hold the line. We make this buffer circular, and end up with the three variables:
1 2 3
char** lines;
char** current;
char** end;
current is used to iterate through the lines, and end is to know when the end of the array is found so that current will go back to the start (lines).
Pointer arithmetic already accounts for different object sizes, it's not your job to do that.
The only reason sizeof(char) "works" is because it is 1 by definition and thus the multiplication does not affect the result.
Now for the printing part. 'end' is the last line of the array and it is a valid address. Is this safe?
1 2 3 4 5 6 7 8 9 10 11
void print(void)
{
char** iter;
if (current == NULL || current == lines)
{
iter = lines;
while (*iter != NULL || iter == end + 1)
std::cout << *iter++ << std:endl;
}
// The tricky part goes here
}
In particular: iter == end + 1
Edit: other than the bug you may see when the initial amount is greater than the amount of lines actually read :)
Having a pointer to the element just one past the array is allowed. However, dereferencing it is not and incrementing it further is not allowed either. It seems you meant if (iter != end + 1 && *iter != NULL)
#include "lineholder.h" // Function definitions and #include <iostream>
#define NULL 0
#define MAX_LINES 1000
char** lines = NULL;
char** current = NULL;
char** end = NULL;
int createLines(unsignedint amount)
{
/* General Safety */
if (lines != NULL || amount == 0) return -1;
amount = (amount < MAX_LINES? amount: MAX_LINES);
/* Create Lines */
lines = newchar*[amount];
/* Define important positions*/
current = lines;
end = lines + (amount - 1);
/* Set array to NULL*/
char** iter = lines;
while (iter <= end)
{
*iter++ = NULL;
}
return 0;
}
void destroyLines(void)
{
/* General Safety */
if (lines == NULL) return;
/* Create an Iterator */
char** iter = lines;
/* Delete each line */
while (iter <= end)
{
if (*iter != NULL)
delete [] *iter;
iter++;
}
/* Delete entire Array */
delete [] lines;
/* Reset Variables */
lines = NULL;
current = NULL;
end = NULL;
}
int addLine(constchar* line)
{
/* Delete an existing line */
if (*current != NULL) delete [] *current;
/* Allocate Space and Copy line */
*current = newchar[myStrlen(line) + 1];
myStrcpy(*current, line);
/* Move Current */
if (current == end)
{
current = lines;
}
else
{
current++;
}
return 0;
}
void print(void)
{
/* Create an Iterator */
char** iter;
/* If the file was smaller than the allocated array
* Or the array size was divisible by the lines in the file */
if (*current == NULL || current == lines)
{
iter = lines;
while (iter != end + 1 && *iter != NULL)
{
std::cout << *iter++ << std::endl;
}
}
else /* We have read over the array more than once
* And current is somewhere in the middle of it */
{
iter = current;
do
{
std::cout << *iter << std::endl;
if (iter == end) iter = lines;
else iter++;
}
while (iter != current);
}
}
unsignedint myStrlen(constchar* str)
{
constchar* pos = str;
while (*str++)
;
return str - pos - 1;
}
void myStrcpy(char* dest, constchar* source)
{
while (*dest++ = *source++)
;
}