Relatively new to programming, been assigned to a task to create a C program to encode and decode 2 ppm images to receive a secret message. I've came up with code but its not getting past the image format if statement in the getPPM function. Any tips on what changes I could make to my code? Also in my main(), am I passing in the correct parameters?
typedef struct NODE {
char *val;
struct NODE *next;
} NODE;
/*
Stores the RGB values of a pixel
*/
typedef struct Pixel {
int red;
int green;
int blue;
} Pixel;
/*
Stores the contents of a PPM file
*/
typedef struct PPM {
char *format;
NODE *comments;
int width, height;
int max;
Pixel *arr;
} PPM;
NODE *copy(NODE *first)
{
NODE *second = NULL, *previous = NULL;
while (first != NULL) {
NODE *temp = (NODE *)malloc(sizeof(NODE));
temp->val = first->val;
temp->next = NULL;
if (second == NULL) {
second = temp;
previous = temp;
} else {
previous->next = temp;
previous = temp;
}
first = first->next;
}
return second;
}
//Copy the PPM File Returning Pointer
struct PPM* createPPM(PPM *old)
{
PPM* new = (PPM *)malloc(sizeof(PPM));
strcpy(new->format, old->format);
new->comments = copy(old->comments);
new->height = old->height;
new->width = old->width;
new->max = old->max;
new->arr = (Pixel *)malloc(old->height * old->width * sizeof(Pixel));
memcpy(new->arr, old->arr, old->height * old->width * sizeof(Pixel));
return new;
}
/*
Returns the PPM struct from the file fd
*/
PPM *getPPM(FILE *fd) {
PPM *image = (PPM *)malloc(sizeof(PPM));
image->format = (char *)malloc(MAX_LEN);
fgets(fd, MAX_LEN, image->format);
sscanf(fd, "%s", image->format);
if (strcmp(image->format, "P3") != 0) {
printf("Invalid Image Type");
exit(0);
}
char c = getc(fd);
image->comments = (NODE*)malloc(sizeof(NODE));
NODE *temp = image->comments;
while ((c = getc(fd)) == '#') {
fseek(fd, -1, SEEK_CUR);
char str[50];
fgets(str, 50, fd);
temp->val = (char*)malloc(strnlen(str, 50));
strcpy(temp->val, str);
temp->val[strlen(temp->val) - 1] = 0;
temp->next = (NODE*)malloc(sizeof(NODE));
temp = temp->next;
temp->next = NULL;
}
fseek(fd, -1, SEEK_CUR);
fscanf(fd, "%d", &image->width);
fscanf(fd, "%d", &image->height);
fscanf(fd, "%d", &image->max);
image->arr = (Pixel*)malloc(image->height * image->width * sizeof(Pixel));
int t = 0;
int j = 0;
while (j < image->height * image->width) {
t = fscanf(fd, "%d", &image->arr[j].red);
t = fscanf(fd, "%d", &image->arr[j].green);
t = fscanf(fd, "%d", &image->arr[j].blue);
j = j + 1;
}
return image;
}
PPM *loadPPMFromFile(char *filename) {
FILE *file;
/* TODO: step 1, open the file */
file = fopen("C:\\Users\\Olivia\\source\\repos\\f28hs-2020-21-cwk1-c\\PPMfiles", "r");
/* step 2: Check that file has been loaded correctly; show error otherwise*/
if (file != NULL) {
PPM *ppm;
/* ODO: step 3, get the PPM data from the file with the getPPM function */
getPPM(file);
if (ppm == NULL) {
/* TODO: step 4, display error if file cannot been parsed into a PPM struct*/
printf("File cannot be parsed.\n");
}
/* TODO: step 5, close the file */
fclose(file);
/* step 6: return the PPM */
return ppm;
} else {
fclose(file);
return NULL;
}
}
/*
Prints a PPM struct in the format of a PPM file
*/
void showPPM(PPM *ppm) {
printf("%s\n", ppm->format); //print format
//print comments
NODE *n = ppm->comments;
while (n->next != NULL) {
printf("%s\n", n->val);
n = n->next;
}
//print width, height and max
printf("%d %d\n%d\n", ppm->width, ppm->height, ppm->max);
//print the array containing the pixels
int j;
for (j = 0; j < ppm->height * ppm->width; ++j) {
printf("%d %d %d\n", ppm->arr[j].red, ppm->arr[j].green, ppm->arr[j].blue);
}
return;
}
/*
Encodes text into red field of PPM
Returns the encoded PPM
*/
PPM *encode(char *text, PPM *i) {
PPM *str = createPPM(i);
int random;
srand((unsigned)time(NULL));
int randMax = (i->height * i->width) / (strlen(text) + 1);
random = rand() % randMax;
if (random < 1) {
random = 1;
}
int k = 0;
int j = random;
//Red fields swapped with ASCII int
while (k < strlen(text)) {
if (str->arr[j].red == text[k]) {
j = j + 1; // if the values are the same we encode in the next pixel.
} else {
str->arr[j].red = text[k];
k = k + 1;
j = j + random;
}
}
return str;
}
/*
Compares 2 PPM structs and decodes the message hidden within
Returns the decoded message if the images have the same dimensions
Returns NULL otherwise
*/
char *decode(PPM *i1, PPM *i2) {
int i = 0;
int j = 0;
char *str = (char*)malloc(sizeof(char));
while (i < i1->height * i1->width) {
if (i1->arr[i].red != i2->arr[i].red) {
str[j] = i2->arr[i].red;
j = j + 1;
}
i = i + 1;
}
str = realloc(str, i);
return str;
printf("%s", str);
}
/* TODO: Question 3 */
int main(int argc, char *argv[]) {
/* check arguments */
switch (argc) {
case 2:
/* TODO: not enough arguments, print an error message */
printf("Not enough arguments. \n");
break;
case 3:
if (strcmp(argv[1], "e") == 0) { //Argument "e" - encode PPM
PPM *ppm = loadPPMFromFile(argv[2]);
createPPM(ppm);
/*Check that PPM is valid; continue if it is, exit otherwise */
if (ppm != NULL) {
PPM *encodedPPM;
/* TODO: encode the ppm with the text and assign to encodedPPM */
encodedPPM = encode(argv[2], encodedPPM);
/*Check that no error occured*/
if (encodedPPM == NULL) {
return EXIT_FAILURE;
} else {
/* TODO: print a confirmation that encoding was successful */
printf("Encoding successful. \n");
/* TODO: print the PPM to standard output with showPPM */
showPPM(encodedPPM);
return EXIT_SUCCESS;
}
} else {
return EXIT_FAILURE;
}
} else {
printf("Unrecognised or incomplete command line.\n");
return EXIT_FAILURE;
}
break;
case 4:
if (strcmp(argv[1], "d") == 0) { //Argument "d" - decode PPM
PPM *comparisonPPM;
PPM *encodedPPM;
/* TODO: get comparison file filename from argv, load it with
loadPPMFromFile then assign to comparisonPPM */
comparisonPPM = loadPPMFromFile(argv[2]);
/* TODO: get encoded file filename from argv, load it with
loadPPMFromFile then assign to encodedPPM */
encodedPPM = loadPPMFromFile(argv[2]);
/*Check both PPMs are valid; continue if so, exit otherwise */
if (comparisonPPM != NULL && encodedPPM != NULL) {
char *decodedMsg;
/* TODO: decode the encodedPPM with the comparisonPPM and assign to decodedMsg */
decodedMsg = decode(encodedPPM, comparisonPPM);
/*Check that the message has been decoded*/
if (decodedMsg != NULL) {
/* TODO: print a confirmation message that the message was decoded */
printf("Decoded message:\n");
/* TODO: print the decoded message */
printf("%p",decodedMsg);
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
} else {
return EXIT_FAILURE;
}
} else {
fprintf(stderr, "Unrecognised or incomplete command line.\n\n");
return EXIT_FAILURE;
}
break;
default:
fprintf(stderr, "Unrecognised or incomplete command line.\n\n");
return EXIT_FAILURE;
}
}
"Also in my main(), am I passing in the correct parameters?"
Yes, they are correct.
"not getting past the image format if statement in the getPPM function"
There are several issues with getPPM.
Overwriting c in the statements following this one:
char c = getc(fd);
is already covered in comments.
In the following:
sscanf(fd, "%s", image->format);
if (strcmp(image->format, "P3") != 0)
{
Because sscanf() will pick up the new line if there is one, strcmp() will fail the comparison for "P3".
Suggestions are to do 1 or more of the following:
running in a debugger, place a break point at the if and view value of image->format
place if(image->format != NULL) printf("%s", image->format) after sscanf()
if you suspect \n or \r\n may be in the buffer, use image->format[strcspn(image->format, "\r\n")] = 0; to remove them.
Regarding the following, suggest you read the documentation on each C function, eg fgets():
This:
fgets(fd, MAX_LEN, image->format);
scanf(...
Should be
if(fgets(image->format, MAX_LEN, fd) != NULL)
{
scanf(...
(Argument positions changed, and test before trying to use buffer.)
Aside: Because this is C, following malloc statements
PPM* image = (PPM*)malloc(sizeof(PPM));
image->format = (char*)malloc(MAX_LEN);
are more correctly written as
PPM* image = malloc(sizeof(*image));
image->format = malloc(MAX_LEN);
(Cast is removed from malloc() and note sizeof argument in the first statement. apply as applicable throughout your code.
Related
I'm trying to read the following file line by line into an array of strings where each line is an element of the array:
AATGC
ATGCC
GCCGT
CGTAC
GTACG
TACGT
ACGTA
CGTAC
GTACG
TACGA
ACGAA
My code is as follows:
void **get_genome(char *filename) {
FILE *file = fopen(filename, "r");
int c;
int line_count = 0;
int line_length = 0;
for (c = getc(file); c != EOF; c = getc(file)) {
if (c == '\n') line_count++;
else line_length++;
}
line_length /= line_count;
rewind(file);
char **genome = calloc(line_length * line_count, sizeof(char));
for (int i = 0; i < line_count; i++) {
genome[i] = calloc(line_length, sizeof(char));
fscanf(file, "%s\n", genome[i]);
}
printf("%d lines of %d length\n", line_count, line_length);
for (int i = 0; i < line_count; i++)
printf("%s\n", genome[i]);
}
However, for some reason I get garbage output for the first 2 elements of the array. The following is my output:
`NP��
�NP��
GCCGT
CGTAC
GTACG
TACGT
ACGTA
CGTAC
GTACG
TACGA
ACGAA
You seem to assume that all lines have the same line length. If such is the case, you still have some problems:
the memory for the row pointers is allocated incorrectly, it should be
char **genome = calloc(line_count, sizeof(char *));
or better and less error prone:
char **genome = calloc(line_count, sizeof(*genome));
the memory for each row should be one byte longer the the null terminator.
\n is the fscanf() format string matches any sequence of whitespace characters. It is redundant as %s skips those anyway.
it is safer to count items separated by white space to avoid miscounting the items if the file contains any blank characters.
you do not close file.
you do not return the genome at the end of the function
you do not check for errors.
Here is a modified version:
void **get_genome(const char *filename) {
FILE *file = fopen(filename, "r");
if (file == NULL)
return NULL;
int line_count = 1;
int item_count = 0;
int item_length = -1;
int length = 0;
int c;
while ((c = getc(file)) != EOF) {
if (isspace(c)) {
if (length == 0)
continue; // ignore subsequent whitespace
item_count++;
if (item_length < 0) {
item_length = length;
} else
if (item_length != length) {
printf("inconsistent item length on line %d\", line_count);
fclose(file);
return NULL;
}
length = 0;
} else {
length++;
}
}
if (length) {
printf("line %d truncated\n", line_count);
fclose(file);
return NULL;
}
rewind(file);
char **genome = calloc(item_count, sizeof(*genome));
if (genome == NULL) {
printf("out of memory\n");
fclose(file);
return NULL;
}
for (int i = 0; i < item_count; i++) {
genome[i] = calloc(item_length + 1, sizeof(*genome[i]));
if (genome[i] == NULL) {
while (i > 0) {
free(genome[i]);
}
free(genome);
printf("out of memory\n");
fclose(file);
return NULL;
}
fscanf(file, "%s", genome[i]);
}
fclose(file);
printf("%d items of %d length on %d lines\n",
item_count, item_length, line_count);
for (int i = 0; i < item_count; i++)
printf("%s\n", genome[i]);
return genome;
}
char **genome = calloc(line_length * line_count, sizeof(char));
must be
char **genome = calloc(line_count, sizeof(char*));
or more 'secure'
char **genome = calloc(line_count, sizeof(*genome));
in case you change the type of genome
else the allocated block if not enough long if you are in 64b because line_count is 5 rather than 8, so you write out of it with an undefined behavior
You also need to return genome at the end of the function
It was also possible to not count the number of lines and to use realloc to increment your array when reading the file
As I see the lines have the same length. Your function should inform the caller how many lines have been read. There is no need of reading the file twice. There is no need of calloc (which is more expensive function). Always check the result of the memory allocation functions.
Here is a bit different version of the function:
char **get_genome(char *filename, size_t *line_count) {
FILE *file = fopen(filename, "r");
int c;
size_t line_length = 0;
char **genome = NULL, **tmp;
*line_count = 0;
if(file)
{
while(1)
{
c = getc(file);
if( c == EOF || c == '\n') break;
line_length++;
}
rewind(file);
while(1)
{
char *line = malloc(line_length + 1);
if(line)
{
if(!fgets(line, line_length + 1, file))
{
free(line);
break;
}
line[line_length] = 0;
tmp = realloc(genome, (*line_count + 1) * sizeof(*genome));
if(tmp)
{
genome = tmp;
genome[*line_count] = line;
*line_count += 1;
}
else
{
// do some memory free magic
}
}
}
fclose(file);
}
return genome;
}
I'm having problems with my C program which works perfectly on Windows but not on Linux. I use the following method for reading line by line a file:
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead){
char *line; // buffer for our string
int ch; // we will read line character by character
size_t len = 0; // number of characters read (character counter)
size_t lineSize = typicalSize; // initial size of the buffer allocated for the line
*nrOfCharRead = 0;
if(!fp) return NULL; // protection
// allocating the buffer
line = realloc(NULL, sizeof(char)*lineSize); // expected size of the line is pathHead to typicalSize
if (!line) return line; // protection, if we fail to allocate the memory we will return NULL
while (1) { // loop forever
ch = fgetc(fp); // getting character by character from file
if (ch == '\n') break; // end of line detected - breaking the loop
if( ch == EOF) {
*endOfLineDetected = 1;
break; // end of file detected - breaking the loop
}
line[len++] = ch; // store the character in the line buffer, increase character counter
if (len == lineSize){ // we reached the end of line buffer (no more room)
lineSize = lineSize + 64; // we have to increase the line size
line = realloc(line, sizeof(char)*(lineSize)); // line buffer has new size now
if (!line) return line; // if we fail to allocate memory we will return NULL
}
if( (len == 0) && *endOfLineDetected){ // empty file
*endOfLineDetected = 1;
break;
}
}
line[len++] ='\0'; // ending the string (notice there is no '\n' in the string)
*nrOfCharRead = len;
return line; // return the string
}
The workflow of my program is the following: I gave in input a path, the file correspondent to the path contains in each line others file path that I read with the function above and put into a structure. On each i apply the KMP algorithm to get the occurrences of a string.
The problem comes in my program when I try to open the files that correspond to the paths I saved earlier:
FILE *fp = NULL;
fp = fopen(list->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", list->path);
exit(1);
}
On the screen is displayed:
, exiting ...
This is so weird because of file opening problem the output should be:
Cannot open "list->path content", exiting. . .
Even though I don't know why it gives me this error while opening the path read from the input file. During compiling there's no problem. I was thinking about buffer problems derived by the function "getLineOfAnySize. I'm not a Linux user, I was just trying to run the program in order to make sure it will run on both OS. Don't think about design issues or logical issues because on Windows everything works perfectly. Big up to everyone who will help me! Please ask further information about the code if needed.
EDIT:
The content of the input file is:
/home/xxx/Scrivania/find/try
/home/xxx/Scrivania/find/try1
Note that find is the directory of the project.
The following is a sample of my program in order to make more sense of variable and construct:
foo.c :
#include "foo.h"
FILE *fInput = NULL;
FILE *fp = NULL;
char *line1;
char *line2;
int endOfLineDetected = 0;
size_t nrOfCharRead = 0;
char ch;
fWord *w = NULL;
fWord *wordHead = NULL;
fWord *wordTail = NULL;
fList *list = NULL;
fList *listHead = NULL;
fList *listTail = NULL;
fPath *pathHead = NULL;
fPath *pathTail = NULL;
fPosition *positionHead = NULL;
fPosition *head = NULL;
fPosition *current = NULL;
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead);
int main(int argc, char *argv[]){
fInput = fopen(argv[1], "r"); //the file that contains the path of the file in which search.
if(fInput == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", argv[1]);
exit(1);
}
while(!endOfLineDetected){ //read line by line the input file in order to save the path in a structure
line1 = getLineOfAnySize(fInput,128,&endOfLineDetected,&nrOfCharRead);
fList *node = malloc (sizeof(fList));
node->path = line1;
node->next = NULL;
if(listHead == NULL){
listHead = listTail = node;
}else{
listTail = listTail->next = node;
}
}
list = listHead;
fclose(fInput);
do{
fWord *app = malloc(sizeof(fWord));
printf("Insert the word to search: ");
scanf("%s", app->word);
app->totalOccurences = 0;
app->p = NULL;
app->next = NULL;
if(wordHead == NULL){
wordTail = wordHead = app;
}else{
wordTail = wordTail->next = app;
}
printf("Do you want to insert another word? (Y/N): ");
scanf(" %c", &ch);
}while(ch == 'y' || ch == 'Y');
w = wordHead;
while(w != NULL){
while(list != NULL){
w->p = malloc(sizeof(fPath));
w->p->fileOccurrences = 0;
w->p->path = list->path;
w->p->position = NULL;
w->p->next = NULL;
if(pathHead == NULL){
pathTail = pathHead = w->p;
}else{
pathTail = pathTail->next = w->p;
}
fp = fopen(w->p->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", w->p->path);
exit(1);
}
int countLine = 0;
endOfLineDetected = 0;
while(!endOfLineDetected){
line2 = getLineOfAnySize(fp,128,&endOfLineDetected,&nrOfCharRead);
int n = strlen(line2);
int m = strlen(w->word);
w->p->fileOccurrences = w->p->fileOccurrences + KMP(line2, w->word, n, m, countLine, w->p);
countLine = countLine + 1;
}
w->totalOccurences = w->totalOccurences + w->p->fileOccurrences;
w->p->position = getHead();
w->p = w->p->next;
list = list->next;
fclose(fp);
}
w->p = pathHead;
list = listHead;
w = w->next;
pathHead = NULL;
}
w = wordHead;
while(w != NULL){
printf("WORD %s \r\n", w->word);
printf("TOTAL %d \r\n", w->totalOccurences);
pathHead = w->p;
while(w->p != NULL){
printf("FILE %s \r\n", w->p->path);
printf("OCCURENCES %d \r\n", w->p->fileOccurrences);
positionHead = w->p->position;
while (w->p->position != NULL){
printf("%d %d\r\n", w->p->position->line, w->p->position->character);
w->p->position = w->p->position->next;
}
w->p->position = positionHead;
w->p = w->p->next;
}
w->p = pathHead;
w = w->next;
}
w = wordHead;
printf("\r\n");
freeMemory();
freeKMP();
return 0;
}
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int
*endOfLineDetected,size_t *nrOfCharRead){
char *line; // buffer for our string
int ch; // we will read line character by character
size_t len = 0; // number of characters read (character counter)
size_t lineSize = typicalSize; // initial size of the buffer allocated for the line
*nrOfCharRead = 0;
if(!fp) return NULL; // protection
// allocating the buffer
line = realloc(NULL, sizeof(char)*lineSize); // expected size of the line is pathHead to typicalSize
if (!line) return line; // protection, if we fail to allocate the memory we will return NULL
while (1) { // loop forever
ch = fgetc(fp); // getting character by character from file
if (ch == '\n') break; // end of line detected - breaking the loop
if( ch == EOF) {
*endOfLineDetected = 1;
break; // end of file detected - breaking the loop
}
line[len++] = ch; // store the character in the line buffer, increase character counter
if (len == lineSize){ // we reached the end of line buffer (no more room)
lineSize = lineSize + 64; // we have to increase the line size
line = realloc(line, sizeof(char)*(lineSize)); // line buffer has new size now
if (!line) return line; // if we fail to allocate memory we will return NULL
}
if( (len == 0) && *endOfLineDetected){ // empty file
*endOfLineDetected = 1;
break;
}
}
line[len++] ='\0'; // ending the string (notice there is no '\n' in the string)
*nrOfCharRead = len;
return line; // return the string
}
// Function to implement KMP algorithm
int KMP(const char* X, const char* Y, int m, int n, int line, fPath *app){
int count = 0;
// next[i] stores the index of next best partial match
int next[n + 1];
for (int i = 0; i < n + 1; i++)
next[i] = 0;
for (int i = 1; i < n; i++){
int j = next[i + 1];
while (j > 0 && Y[j] != Y[i])
j = next[j];
if (j > 0 || Y[j] == Y[i])
next[i + 1] = j + 1;
}
for (int i = 0, j = 0; i < m; i++){
if(X[i] == Y[j]){
if (++j == n){
count = count + 1; //conta le occorrenze della parola nella riga in input
fPosition *node = malloc (sizeof(fPosition));
node->line = line;
node->character = i - j + 1;
node->next = NULL;
if(head == NULL){
current = head = node;
}else{
current = current->next = node;
}
app->position = current;
}
}
else if (j > 0) {
j = next[j];
i--; // since i will be incremented in next iteration
}
}
return count;
}
fPosition * getHead(){ //rimette il puntatore alla testa della lista
fPosition *app = head;
head = NULL;
return app;
}
void freeKMP(){
free(head);
free(current);
}
void freeMemory(){
list = listHead;
fList *tempL = NULL;
while(list != NULL){
tempL = list;
list = list->next;
free(tempL);
}
w = wordHead;
fWord *tempW = NULL;
fPath *tempP = NULL;
fPosition *tempO = NULL;
while(w != NULL){
while(w->p != NULL){
while(w->p->position != NULL){
tempO = w->p->position;
w->p->position = w->p->position->next;
free(tempO);
}
tempP = w->p;
w->p = w->p->next;
free(tempP);
}
tempW = w;
w = w->next;
free(tempW);
}
free(w);
free(line1);
free(line2);
free(wordHead);
free(wordTail);
free(listHead);
free(listTail);
free(pathHead);
free(pathTail);
free(positionHead);
}
foo.h:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct fileList{
char *path;
struct fileList *next;
};
struct filePath{
char *path;
int fileOccurrences;
struct OccurrencesPosition *position;
struct filePath *next;
};
struct fileWord{
char word[50];
int totalOccurences;
struct filePath *p;
struct fileWord *next;
};
struct OccurrencesPosition{
int line;
int character;
struct OccurrencesPosition *next;
};
typedef struct filePath fPath;
typedef struct fileWord fWord;
typedef struct OccurrencesPosition fPosition;
typedef struct fileList fList;
fPosition * getHead();
int KMP(const char* X, const char* Y, int m, int n, int line, fPath *app);
void freeMemory();
void freeKMP();
Maybe also the way I free memory isn't correct.
This is not a full answer, but a hint for further analysis.
I tested the program with the input file contents as shown in the question and entered one or two words.
If the first file does not exist, I get an error message as expected:
Cannot open /home/yuripaoloni/Scrivania/find/try, exiting. . .
Then I modified the input file to list two files that exist on my system and get an error message
Cannot open , exiting. . .
I extended the code that tries to open the file to get more output:
fp = fopen(w->p->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", w->p->path);
perror("fopen");
exit(1);
} else {
printf("Successfully opened %s\n", w->p->path);
}
This prints
$ ./foo input
Insert the word to search: foo
Do you want to insert another word? (Y/N): y
Insert the word to search: bar
Do you want to insert another word? (Y/N): y
Insert the word to search: baz
Do you want to insert another word? (Y/N): n
Successfully opened /home/username/tmp/try
Successfully opened /home/username/tmp/try1
Cannot open , exiting. . .
fopen: No such file or directory
Apparently your program tries to open a third file after the existing file names. w->p->path might be a NULL pointer or may point to an empty string.
The same error occurs when I enter only one word. I did not further analyze the error.
To find out why your program tries to open a file with an empty name, you can run it in a debugger or add more output to see how many loop cycles are executed when processing the lists and which data you find.
Incorrect code to check if a word can be made of smaller given words (word break).This is the code I wrote for the above mentioned problem, however an online judge declares it as incorrect, what could be the possible reasons? And how should I modify my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Node structure */
typedef struct node {
int letter[26];
struct node* next[26];
int is_word;
} node;
/* Create node */
node* getnode(void) {
node* p = malloc(sizeof(node));
int i;
for (i = 0; i < 1004; i++) {
p->letter[i] = 0;
p->next[i] = NULL;
}
p->is_word = 0;
return p;
}
/* make dictionary */
void fill_dictionary(char word[], node* start) {
int len = strlen(word), i;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[word[i] % 'a'] == 0) {
temp->letter[word[i] % 'a'] = 1;
temp->next[word[i] % 'a'] = getnode();
temp = temp->next[word[i] % 'a'];
} else {
temp = temp->next[word[i] % 'a'];
}
}
temp->is_word = 1;
return;
}
int spell_check(char line[100003], node* start) {
int len = strlen(line), i, flag = 0;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[line[i] % 'a'] == 0) {
return 1;
} else {
temp = temp->next[line[i] % 'a'];
flag = 0;
if (temp->is_word == 1) {
flag = 1;
temp = start;
}
}
}
if (flag == 1) {
return 0;
} else {
return 1;
}
}
int main(void) {
int n, i, ans, m;
scanf("%d %d", &n,&m); // no. of words in dictionary
node* start = getnode();
for (i = 0; i < n; i++) {
char word[11]; // max length of dictionary word
scanf("%s", word);
fill_dictionary(word, start);
}
scanf("%d", &n); // no. of lines to be checked
for (i = 0; i < n; i++) {
char line[100003]; // max length of a line
scanf("%s", line);
ans = spell_check(line, start);
if (ans == 0) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
Here's one way to to it. This compiles and runs. It displays the parsed result. It tries to read the dictionary from a file called "dictionary.text" in the current directory. You can change it to put the dictionary wherever you want. I commented it heavily to help you understand it but it has some subtle C things you may need to really think about and figure out. One bit of advice: Name everything in a program as extremely accurately for what it is/does as possible (but reasonably succinct). That will help immensely when trying to debug or figure out what you did wrong. Careless names really make code confusing and hard to debug.
Good luck!
Example:
$ gcc -o wordsplitter wordsplitter.c
$ wordsplitter xyzhellogoodbyefoodogcatpigcarwhereareyouhorse
xyz "hello" "goodbye" foo "dog" "cat" pigcar "where" "are" "you" horse
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DICTIONARY_FILEPATH "dictionary.txt"
#define MAX_WORD_SIZE 100
/*
* Error codes (usually this is put in a header file and included)
*/
#define SUCCESS 0
#define FILE_NOT_FOUND -1
#define OUT_OF_MEMORY -2
typedef struct word {
struct word *next;
char *word;
} word_t;
word_t *dictionaryListhead = NULL;
typedef struct wordsubcomponent {
struct wordsubcomponent *next;
char *text;
int isDictionaryWord;
} wordsubcomponent_t;
int
loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
wordsubcomponent_t
*newsubcomponent() {
wordsubcomponent_t *subcomp = NULL;
if ((subcomp = calloc(sizeof(wordsubcomponent_t), 1)) != NULL) {
subcomp->text = strdup(""); // seed with empty string (instead of NULL) so we can append
} else {
fprintf(stderr, "out of memory (fatal). program exiting\n");
exit(-1);
}
return subcomp;
}
/*
* Returns an linked list of word subcomponents for the given word, split up around dictionary words
*/
wordsubcomponent_t *getWordSubcomponents(char *wordToParse, word_t *listhead) {
wordsubcomponent_t *subcomponents, *currSubcomp;
subcomponents = currSubcomp = newsubcomponent();
for (char *cp = wordToParse; cp < wordToParse + strlen(wordToParse);) { // exit when cp gets to end of word to parse.
int matchFlag = 0;
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
if (strncasecmp(cp, wordNode->word, strlen(wordNode->word)) == 0) { // prefix of cur. ptr is dict word.
if (strlen(currSubcomp->text) != 0) // Detected non-dict text in subcomp.
currSubcomp = currSubcomp->next = newsubcomponent(); // leave in list & add new subcomp for dict word.
currSubcomp->text = wordNode->word; // save dict-word in subcomp
currSubcomp->isDictionaryWord = 1;
currSubcomp = currSubcomp->next = newsubcomponent(); // dict-word in list, so get new subcomp
cp += strlen(wordNode->word); // advance cp past extracted dict-word
matchFlag = 1;
break; // break out of inner-loop
}
}
if (!matchFlag) { // No dict-word found at cp
char oneNullTerminatedLetter[2] = { *cp++, '\0' }; // put 1st ltr into NULL-terminated string & adv cp.
strcat(currSubcomp->text, oneNullTerminatedLetter); // append letter-as-string to curr subcomp
}
}
return subcomponents;
}
void
dumpDictionary(word_t *listhead) {
printf("\nList of dictionary words:\n");
printf("----------------\n");
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
printf(" %s\n", wordNode->word);
}
printf("----------------\n\n");
}
int
main(int argc, char **argv)
{
int status;
if ((status = loadDictionaryFromFile(DICTIONARY_FILEPATH, &dictionaryListhead)) < 0) {
switch(status) {
case FILE_NOT_FOUND:
fprintf(stderr, "Error accessing dictionary: %s\n", argv[0]);
break;
case OUT_OF_MEMORY:
fprintf(stderr, "Out of memory");
break;
}
return EXIT_FAILURE;
}
/*
* Load dictionary first so we can show them the list of words if they didn't
* pass in a command line argument with the word to parse.
*/
if (argc < 2) {
fprintf(stderr, "Usage: %s <word_to_parse>\n\n", argv[0]);
dumpDictionary(dictionaryListhead);
return EXIT_FAILURE;
}
wordsubcomponent_t *subcomp = getWordSubcomponents(argv[1], dictionaryListhead);
while(subcomp != NULL && strlen(subcomp->text) > 0) {
if (subcomp->isDictionaryWord)
printf("\"%s\" ", subcomp->text);
else
printf("%s ", subcomp->text);
subcomp = subcomp->next;
}
printf("\n");
return EXIT_SUCCESS;
}
#nerdist colony:
There is a resource leak in loadDictionaryFromFile. This means a file pointer was not closed when returning from this function in case of an error.
Here is a corrected copy of this function
int loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
fclose(dictionaryFile); // <-- Close the file pointer
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
this is an assignment for my CS course,
im trying to write a code that reads a file line by line and put the input into a struct element.the struct looks like this:
typedef char* Name;
struct Room
{
int fStatus;
Name fGuest;
};
the status is 0 for available and 1 for booked. the name will be empty if the room is available.
there are 2 function, one to read and put the values to a struct element, and the other one to print it out.
int openRoomFile()
{
FILE *roomFile;
char *buffer = NULL;
size_t length = 0;
size_t count = 0;
roomFile = fopen("roomstatus.txt", "r+");
if (roomFile == NULL)
return 1;
while (getline(&buffer, &length, roomFile) != -1) {
if (count % 2 == 0) {
sscanf(buffer, "%d", &AllRooms[count].fStatus);
} else {
AllRooms[count].fGuest = buffer;
}
count++;
}
fclose(roomFile);
free(buffer);
return 0;
}
print function
void printLayout(const struct Room rooms[])
{
for (int i=0; i<3; i++) {
printf("%3d \t", rooms[i].fStatus);
puts(rooms[i].fGuest);
}
}
the output is not what i expected, given the input file is :
1
Johnson
0
1
Emilda
i will get the output :
1 (null)
0
0 (null)
i dont know what went wrong, am i using the right way to read the file? every code is adapted from different sources on the internet.
Here is a fixed version of the openRoomFile()
int openRoomFile(void)
{
FILE *roomFile;
char *buffer = NULL;
size_t length = 0;
size_t count = 0;
roomFile = fopen("roomstatus.txt", "r+");
if (roomFile == NULL)
return 1;
while (1) {
buffer = NULL;
if (getline(&buffer, &length, roomFile) == -1) {
break;
}
sscanf(buffer, "%d", &AllRooms[count].fStatus);
free(buffer);
buffer = NULL;
if (getline(&buffer, &length, roomFile) == -1) {
fprintf(stderr, "syntax error\n");
return 1;
}
AllRooms[count].fGuest = buffer;
count++;
}
fclose(roomFile);
return 0;
}
When you no longer need those fGuest anymore, you should call free on them.
If your input is guaranteed to be valid (as were many of my inputs in my CS classes), I'd use something like this for reading in the file.
while(!feof(ifp)){
fscanf(ifp,"%d%s",&AllRooms[i].fStatus, AllRooms[i].fGuest); //syntax might not be right here
//might need to play with the '&'s
//and maybe make the dots into
//arrows
//do work here
i++;
}
You are not allocating memory for Name. Check this. In the below example i'm not included free() calls to allocated memory. you need to call free from each pointer in AllRooms array, once you feel you are done with those and no more required.
#include<stdio.h>
#include<stdlib.h>
typedef char* Name;
struct Room
{
int fStatus;
Name fGuest;
}Room_t;
struct Room AllRooms[10];
int openRoomFile()
{
FILE *roomFile;
char *buffer = NULL;
size_t length = 0;
size_t count = 0;
size_t itemCount = 0;
roomFile = fopen("roomstatus.txt", "r+");
if (roomFile == NULL)
return 1;
buffer = (char *) malloc(16); // considering name size as 16 bytes
while (getline(&buffer, &length, roomFile) != -1) {
if (count % 2 == 0) {
sscanf(buffer, "%d", &AllRooms[itemCount].fStatus);
} else {
AllRooms[itemCount].fGuest = buffer;
itemCount++;
}
count++;
buffer = (char *) malloc(16); // considering name size as 16 bytes
}
fclose(roomFile);
free(buffer);
return 0;
}
void printLayout(const struct Room rooms[])
{
int i;
for (i=0; i<3; i++) {
printf("%3d \t", rooms[i].fStatus);
puts(rooms[i].fGuest);
}
}
int main(void)
{
openRoomFile();
printLayout(AllRooms);
// free all memory allocated using malloc()
return 0;
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Doing a homework and I'm having problems with, what I believe, pointers.
The assignment consists in the following:
I have a txt file where each line as a name and a password.
thisismyname:thisismypassword
I have to read this data, process it into struct linked list, run all the list and send the password to a brute-force algorithm. This algorithm, after finding the pass, should write the pass on the struct. In the end, I should run the list and write the data to a txt file
My problem is when I find the password. It is not storing its value in the struct. At the end I can read the data, I can see that the brute-force is working but at the end, I'm only managing to write the name and pass to file. The unencrypted pass is being written as NULL so I believe is a pointer problem.
This is the code (Removed all the things that I believe are irrelevant):
typedef struct p {
char *name;
char *pass;
char *pass_desenc;
struct p *next_person;
} person;
typedef struct n {
int a;
int b;
} numbers;
int readFile(person **people) {
FILE * fp;
char line[100];
if ((fp = fopen(STUDENTS_FILE, "r")) != NULL) {
while (fgets(line, sizeof (line), fp) != NULL) {
person *p;
char email[27] = "";
char password[14] = "";
char *change = strchr(line, '\n');
if (change != NULL)
*change = '\0';
/* Gets email*/
strncpy(email, line, 26);
email[27] = '\0';
/* Gets pass*/
strncpy(password, line + 27, 14);
password[14] = '\0';
p = (person*) malloc(sizeof (person));
if (p == NULL) {
return -1;
}
p->name = (char*) malloc(strlen(email));
if (p->name == NULL) {
return -1;
}
sprintf(p->name, "%s", email);
p->name[strlen(email)] = '\0';
p->pass = (char*) malloc(strlen(password));
if (p->pass == NULL) {
return -1;
}
sprintf(p->pass, "%s", password);
p->pass[strlen(password)] = '\0';
p->next_person = (*people);
(*people) = p;
countPeople++;
}
fclose(fp);
return 0;
}
return -1;
}
void fmaps(int id, numbers pass_range, person *people) {
/*This function will run all my list and try to uncrypt pass by pass.
On the brute-force pass in unencrypted and when it return to this function, I can print the data.
*/
while (people != NULL && j > 0) {
for (i = 1; i <= PASS_SIZE && notFound == 1; i++) {
notFound = bruteForce(i, people, &total_pass);
}
notFound = 1;
count = count + total_pass;
printf("#####Email: %s Pass: %s PassDesenq: %s \n", people->name, people->pass, people->pass_desenc);
people = people->next_person;
j--;
}
}
void fcontrol(int n, person *people) {
/*This function should write the data to a file
I can see that all data is written as expected but people->pass_desenc is writing/printing NULL
*/
if ((fp = fopen(STUDENTS_LOG_FILE, "a+")) != NULL) {
while (people != NULL) {
printf("#####1111Email: %s Pass: %s PassDesenq: %s \n", people->name, people->pass, people->pass_desenc);
fprintf(fp, "%d%d%d%d%d%d:grupo%d:%s:%s\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 1, people->name, people->pass_desenc);
people = people->next_person;
}
}
fclose(fp);
}
int main() {
/*Struct*/
person *people = NULL;
if (readFile(&people)) {
printf("Error reading file!\n");
return 0;
}
/*Function to send data to brute-force*/
fmaps(i, pass_range, people);
/*After all data is processed, this function writes the data to a file*/
fcontrol(NR_PROC, people);
destroyList(&people);
return 0;
}
int bruteForce(int size, person *people, int *total_pass) {
int i;
char *pass_enc;
int *entry = (int*) malloc(sizeof (size));
char pass[50];
char temp;
pass[0] = '\0';
for (i = 0; i < size; i++) {
entry[i] = 0;
}
do {
for (i = 0; i < size; i++) {
temp = (char) (letters[entry[i]]);
append(pass, temp);
}
(*total_pass)++;
/*Compare pass with test*/
pass_enc = crypt(pass, salt);
if (strcmp(pass_enc, people->pass) == 0) {
people->pass_desenc = (char*) malloc(strlen(pass));
if (people->pass_desenc == NULL) {
return -1;
}
sprintf(people->pass_desenc, "%s", pass);
people->pass_desenc[strlen(pass)] = '\0';
return 0;
}
pass[0] = '\0';
for (i = 0; i < size && ++entry[i] == nbletters; i++) {
entry[i] = 0;
}
} while (i < size);
free(entry);
return 1;
}
void append(char *s, char c) {
int len = strlen(s);
s[len] = c;
s[len + 1] = '\0';
}
void destroyList(person **people) {
person *aux;
printf("\nList is being destroyed.");
while (*people != NULL) {
aux = *people;
*people = (*people)->next_person;
free(aux);
printf(".");
}
printf("\nList destroyed.\n");
}
I believe that the changes being made in fmaps are local and are not passing to main.
Any help is appreciated...
This is how you could code the file reader/parser. It avoids str[n]cpy(), and does all string operations using memcpy() + the offsets + sizes. (which need to be correct in both cases, obviously)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct p {
char *name;
char *pass;
// char *pass_desenc;
struct p *next;
} person;
#define STUDENTS_FILE "students.dat"
unsigned countPeople = 0;
int readFile(person **people) {
FILE * fp;
char line[100];
size_t len, pos;
fp = fopen(STUDENTS_FILE, "r");
if (!fp) {
fprintf(stderr, "Could not open %s:%s\n"
, STUDENTS_FILE, strerror(errno));
return -1;
}
while ( fgets(line, sizeof line, fp) ) {
person *p;
len = strlen(line);
/* remove trailng '\n', adjusting the length */
while (len && line[len-1] == '\n') line[--len] = 0;
/* Ignore empty lines */
if ( !len ) continue;
/* Library function to count the number of characters in the first argument
** *not* present in the second argument.
** This is more or less equivalent to strtok(), but
** 1) it doen not modify the string,
** 2) it returns a size_t instead of a pointer.
*/
pos = strcspn(line, ":" );
/* Ignore lines that don't have a colon */
if (line[pos] != ':') continue;
p = malloc(sizeof *p);
if ( !p ) { fclose(fp); return -2; }
p->next = NULL;
p->name = malloc(1+pos);
if ( !p->name ) { fclose(fp); return -3; } /* this could leak p ... */
memcpy(p->name, line, pos-1);
p->name[pos] = 0;
p->pass = malloc(len-pos);
if ( !p->pass ) {fclose(fp); return -4; } /* this could leak p and p->name */
memcpy(p->pass, line+pos+1, len-pos);
/* Instead of pushing (which would reverse the order of the LL)
** , we append at the tail of the LL, keeping the original order.
*/
*people = p;
people = &p->next ;
countPeople++;
}
fclose(fp);
return 0;
}