Results from string search not printing to console as expected - c

So I have this code which I was working on. The goal is to search for a string in a file and when that string is found it would return the corresponding values in that section of the file. So this is the file in question that is being searched:
So if it finds "AJ" then it would return all the values right up to "22550" and if it finds "TS" then it prints everything after "TS" and after "60500." This is my code in question:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
if (count == 0) {
bookingrec.code = line;
//printf("%s %s",bookingrec.code,book_code);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
bookingrec.grpsize = line;
} else if (count == 2 && found == 1) {
bookingrec.route = line;
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(line, NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = line;
} else if (count == 5 && found == 1) {
bookingrec.package = line;
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(line, NULL);
}
count = count + 1;
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %c", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
The problem is that it only gives me this as the result:
So it finds the file okay but nothing happens so I uncomment a printf which I added to troubleshoot a bit right above my strcmp and get this when I enter for eg. "AJ":
I try another of the two character string. "SH" in this case and get this:
So it seems as if it is accepting any of the codes but prints the first line twice? But also discards everything else. I am a bit stumped as to what is happening. Any ideas?
Update:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char *route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
line[strcspn(line, "\r\n")] = 0; //trims getLine
//printf("line is %s, count is %d \n", line, count);//debugging
if (count == 0) {
bookingrec.code = strdup(line);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
char *tmp;
bookingrec.grpsize = strtol(strdup(line), NULL, 10);
} else if (count == 2 && found == 1) {
bookingrec.route = strdup(line);
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(strdup(line), NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = strdup(line);
} else if (count == 5 && found == 1) {
bookingrec.package = strdup(line);
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(strdup(line), NULL);
}
count = count + 1;
if (found == 1 && count == 7){
break;
}
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %s", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
Updated screens after edits:

Related

Stack smashing in file io in c

void issueBook(){
printf("Hii!\n");
//printf("Enter your student ID: ");
//int stdID;
//scanf("%d", &stdID);
printf("Enter the book ID\n");
int bookID;
scanf("%d", &bookID);
FILE *in_file = fopen("recordLib.txt", "r");
FILE *fp = fopen("temp.txt", "w");
struct stat sb;
stat("recordLib.txt", &sb);
char *file_contents = malloc(1024);
int mark = 0;
char ID[] = "";
while (fscanf(in_file, "%[^\n] ", file_contents) != EOF) {
int size = strlen(file_contents);
int countCom = 0;
char ID[] = "";
//printf("%d\n", size);
if(mark == 0){
for(int i=0; i<size; i++){
//printf("asdfsd\n");
//printf("%c", file_contents[i]);
if(countCom == 0 && (file_contents[i] != ',')){
strncat(ID, &file_contents[i], 1);
//printf("%c\n", file_contents[i]);
}
else if(atoi(ID) != bookID){
break;
}
else if((file_contents[i] == ',') && (countCom < 3) && (atoi(ID) == bookID)){
//printf("%c\n", file_contents[i]);
//printf("%s\n", ID);
countCom++;
}
else{
//printf("%c\n", file_contents[i]);
if(file_contents[i] == '1'){
printf("Sorry!! someone has already issued the book");
mark = 2;
break;
}
else if(file_contents[i] == '0'){
file_contents[i] = '1';
mark = 1;
break;
}
}
}
}
fwrite(file_contents, 1, size, fp);
fwrite("\n", 1, 1, fp);
}
fclose(fp);
fclose(in_file);
remove("recordLib.txt");
rename("temp.txt", "recordLib.txt");
//printf("%d\n", s);
//if(mark == 1){
// updateStu();
//}
free(file_contents);
}
I have made this function which takes the bookID from the user and then searches for it in the file:
Searching: It reads line by line and as we already know till first comma ',' it would be book ID so it will store in another string and then convert it to int. Now it will compare it with entered ID if it matches then it will update the 0 at the end to 1, else move to next line.
Error: I always getting stack smashing error when the function again returns to the main function. I am unable to find the thing that is causing the error. Also that when I run in VS code, it runs successfully but in Linux this problem occurs! Please help. Thanks in advance.

How can I input a word, read through a dictionary, and print the word's translation?

My objective is to input a string "sana" which will at the end print only one corresponding result. Ie: if I enter the word "sana" it would print "Word sana is in English word" and if the user enters "word" it prints "Word word is in Finnish sana". So the code is not working at all so I wanted to ask how should I continue. if-else doesn't work at all but I thought it would help me visualize where to go there.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Read file line by line
split lines using ; as delimiter
store first/second part in some array
ask user to input and search the word in that array
*/
int main()
{
FILE *fp;
char sana[30];
char *p;
void *tmp;
int lasku = 0;
int pal = 1;
int i;
char **vars = NULL;
char **vals = NULL;
fp = fopen("dictionary.txt", "r");
printf("Word: ");
scanf("%s", sana);
while (fgets(sana, sizeof(sana), fp)) {
sana[strcspn(sana, "\n")] = 0;
if (!(p = strchr(sana, ';')))
continue;
*p++ = 0; //poistaa ;
if (!strlen(sana) || !strlen(p))
continue;
if (!(tmp = realloc(vars, (lasku + 1) * sizeof(char*))))
goto out;
vars = (char**)tmp;
if (!(tmp = realloc(vals, (lasku + 1) * sizeof(char*))))
goto out;
vals = (char**)tmp;
vars[lasku] = strdup(sana);
vals[lasku] = strdup(p);
lasku++;
if (!vars[lasku-1] || ! vals[lasku-1])
goto out;
}
pal = 0;
if (i == 0 || i == 2 || i == 4)
printf("Word %s is in English %s\n", vars[i], vals[i]);
else
if (i == 1 || i == 3 || i == 5)
printf("Word %s is in Finnish %s\n", vals[i], vars[i]);
else
printf("Word can't be found in the dictionary");
out:
fclose(fp);
if (vars)
for (i = 0; i < lasku; i++)
free(vars[i]);
if (vals)
for (i = 0; i < lasku; i++)
free(vals[i]);
free(vars);
free(vals);
return pal;
}
The code does not work because:
you overwrite the word in sana when you read the dictionary.
you never set i.
testing the value of uninitialized variable i has undefined behavior.
You should first local the dictionary in memory, then read words from the user and search them in the dictionary for matches.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Read file line by line
split lines using ; as delimiter
store first/second part in some array
ask user to input and search the word in that array
*/
int main() {
FILE *fp;
char sana[30];
char **tmp;
int lasku = 0, i, found, error = 0;
char **vars = NULL;
char **vals = NULL;
fp = fopen("dictionary.txt", "r");
while (fgets(sana, sizeof(sana), fp)) {
sana[strcspn(sana, "\n")] = '\0';
if (!(p = strchr(sana, ';')))
continue;
*p++ = '\0';
if (!*sana || !*p)
continue;
if (!(tmp = realloc(vars, (lasku + 1) * sizeof(*vars)))) {
error = 1;
break;
}
vars = tmp;
if (!(tmp = realloc(vals, (lasku + 1) * sizeof(*vals)))) {
error = 1;
break;
}
vals = tmp;
vars[lasku] = strdup(sana);
vals[lasku] = strdup(p);
lasku++;
if (!vars[lasku-1] || !vals[lasku-1]) {
error = 1;
break;
}
}
fclose(fp);
if (!error) {
for (;;) {
printf("Word: ");
if (scanf("%29s", sana) != 1)
break;
found = 0;
for (i = 0; i < lasku; i++) {
if (!strcmp(sana, vars[i]) {
printf("Word %s is in English %s\n", vars[i], vals[i]);
found = 1;
}
if (!strcmp(sana, vals[i]) {
printf("Word %s is in Finnish %s\n", vals[i], vars[i]);
found = 1;
}
}
if (!found) {
printf("Word can't be found in the dictionary");
}
}
}
for (i = 0; i < lasku; i++) {
free(vars[i]);
free(vals[i]);
}
free(vars);
free(vals);
return error;
}

C program runs fine locally, but segfaults on remote server

I have a command line game I wrote that runs properly locally, but segfaults on a remote server. I haven't been able to find out why this is the case.
Local:
Remote:
There clearly is an issue somewhere around where POSSIBLE CONNECTIONS are gathered/displayed.
Here's the full program. This issue may be happening around line 190, as that's where the POSSIBLE CONNECTIONS logic is. I have a feeling it's a problem with my strncpy line, as there is very specific memory manipulation going on there, but I could be wrong.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
struct stat st = {0};
const char * ROOM_NAMES[] = {"Water", "Fire", "Wind", "Earth", "Plasma", "DarkMatter", "Air", "Ice", "Rock", "Lava"};
int i,j;
char directory[20];
char *rooms[7];
int connections[7][7] = {0};
int totalMoves = 0;
char roomChoice[20];
char *movesRecord[100];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void getRoomChoice() {
fflush(stdin);
scanf("%s", roomChoice);
fflush(stdin);
fflush(stdout);
}
void * getTime(void *arg) {
pthread_mutex_lock(&mutex);
FILE *file = fopen("currentTime.txt", "w");
time_t curtime;
struct tm *loc_time;
curtime = time (NULL);
loc_time = localtime (&curtime);
fprintf(file, "%s\n", asctime (loc_time));
// printf("\n%s\n", asctime (loc_time));
fclose(file);
pthread_mutex_unlock(&mutex);
}
void * createRooms() {
// Create directory
int pid = getpid();
char prefix[] = "eldridgt.";
sprintf(directory, "%s%d", prefix, pid);
if (stat(directory, &st) == -1) {
mkdir(directory, 0700);
}
// Create room files
for(i=0; i<7; i++) {
int random;
char filePath[100];
int connectionArr[10];
memset(connectionArr, 0, sizeof connectionArr);
random = rand() % 10; // Random number 0-9
if (connectionArr[random] == 0) { // If room not used
sprintf(filePath,"%s/%s", directory, ROOM_NAMES[random]);
FILE *file = fopen(filePath, "ab+");
fprintf(file, "ROOM NAME: %s\n", ROOM_NAMES[random]); // Add room name
fclose(file);
rooms[i] = ROOM_NAMES[random];
connectionArr[random] = 1; // Room has been used
}
}
return rooms;
}
void * createConnections() {
for(i=0; i<7; i++) {
int connectionCount = rand() % 4 + 3; // Random number 3-6
int currentCount = 0;
for(j=0; j<7; j++) {
currentCount = currentCount + connections[i][j];
}
while (currentCount < connectionCount+1) {
int random = rand() % 7;
while (random == i) {
random = rand() % 7; // If random == current, reset random
}
// Set connections between both rooms
connections[i][random] = 1;
connections[random][i] = 1;
currentCount++;
}
}
}
void * connectionsToFiles() {
for(i=0; i<7; i++) {
int connectionCount = 1;
for(j=0; j<7; j++) {
if(connections[i][j] == 1) {
char filePath[100];
sprintf(filePath,"%s/%s", directory, rooms[i]);
FILE *file = fopen(filePath, "ab+");
fprintf(file, "CONNECTION %d: %s\n", connectionCount, rooms[j]);
fclose(file);
connectionCount++;
}
}
}
}
void * roomTypesToFiles() {
for(i=0; i<7; i++) {
char filePath[100];
sprintf(filePath,"%s/%s", directory, rooms[i]);
FILE *file = fopen(filePath, "a");
switch(i) {
case 0 :
fprintf(file, "ROOM TYPE: START_ROOM\n");
break;
case 6 :
fprintf(file, "ROOM TYPE: END_ROOM\n");
break;
default :
fprintf(file, "ROOM TYPE: MID_ROOM\n");
}
fclose(file);
}
}
isEndRoom(idx) {
movesRecord[totalMoves - 1] = rooms[idx];
char filePath[100];
sprintf(filePath,"%s/%s", directory, rooms[idx]);
char roomType[20];
int lineNumber = 1;
FILE *file = fopen(filePath, "r");
int totaLines = 0;
char line[256];
while(fgets(line, sizeof line, file) != NULL) {
totaLines++; // Line count of room file
}
fclose(file);
file = fopen(filePath, "r");
while(fgets(line, sizeof line, file) != NULL) {
if(lineNumber == totaLines) {
int length = strlen(line) - 11;
strcpy(roomType, line+11);
roomType[length-1] = '\0';
}
lineNumber++;
}
// Check if this is the end room
if(strncmp(roomType, "END", 3) == 0) {
printf("YOU HAVE FOUND THE END ROOM. CONGRATULATIONS!\n");
printf("YOU TOOK %d STEPS. YOUR PATH TO VICTORY WAS:\n", totalMoves - 1);
for(i=1; i<totalMoves; i++) {
printf("%s\n", movesRecord[i]);
}
return 1; // End was reached
} else {
return 0; // End was not reached
}
}
void * playGame(idx) {
totalMoves++;
printf("\n");
if(isEndRoom(idx)) {
exit(0);
}
while(1) {
char filePath[100];
sprintf(filePath,"%s/%s", directory, rooms[idx]);
FILE *file = fopen(filePath, "r");
int totaLines = 0;
char line[100];
while(fgets(line, sizeof line, file) != NULL) {
totaLines++; // Line count of room file
}
fclose(file);
file = fopen(filePath, "r");
int lineNumber = 0;
char *roomChoices[6][20];
while(fgets(line, sizeof line, file) != NULL) { // Current room name
if(lineNumber == 0) {
char roomName[20];
int length = strlen(line) - 11;
strcpy(roomName, line+11);
roomName[length-1] = '\0';
printf("CURRENT LOCATION: %s\n", roomName);
}
else if(lineNumber == 1) { // First room choice option
printf("POSSIBLE CONNECTIONS: ");
fflush(stdout);
char roomName[20];
int length = strlen(line) - 14;
strcpy(roomName, line+14);
roomName[length-1] = '\0';
printf("%s", roomName);
strcpy(roomChoices[lineNumber - 1], roomName);
}
else if(lineNumber > 1 && lineNumber < totaLines - 1) { // Subsequent room choice options
printf(", ");
fflush(stdout);
char roomName[20];
int length = strlen(line) - 14;
strcpy(roomName, line+14);
roomName[length-1] = '\0';
printf("%s", roomName);
fflush(stdout);
strcpy(roomChoices[lineNumber - 1], roomName);
}
else {
printf(".");
fflush(stdout);
}
lineNumber++;
}
fclose(file);
printf("\nWHERE TO? >");
getRoomChoice(); // Get next room choice
if (strcmp(roomChoice, "time") == 0) {
pthread_t thread;
int rc = pthread_create(&thread, NULL, &getTime, NULL);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
pthread_mutex_lock(&mutex);
sleep(1);
FILE *file = fopen("currentTime.txt", "r");
char currentTime[25];
fgets(currentTime, sizeof currentTime, file);
printf("\n%s\n\n", currentTime);
pthread_mutex_unlock(&mutex);
} else {
for(i=0; i<totaLines-2; i++) {
if(strcmp(roomChoices[i], roomChoice) == 0) {
for(j=0; j<7; j++) {
if(strcmp(rooms[j], roomChoice) == 0) { // If the room is equal to roomChoice
playGame(j); // Make playGame call for new room
}
}
}
}
printf("\nHUH? I DON’T UNDERSTAND THAT ROOM. TRY AGAIN.\n\n");
fflush(stdout);
fflush(stdin);
}
}
}
int main() {
createRooms();
createConnections();
connectionsToFiles();
roomTypesToFiles();
playGame(0);
return 0;
}
I too got segfault and tried to fix the code. Now it did run after some changes.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <memory.h>
struct stat st = {0};
char *ROOM_NAMES[] = {"Water", "Fire", "Wind", "Earth", "Plasma", "DarkMatter", "Air", "Ice", "Rock", "Lava"};
int i, j;
char directory[20];
char *rooms[7];
int connections[7][7] = {0};
int totalMoves = 0;
char roomChoice[20];
char *movesRecord[100];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void getRoomChoice() {
fflush(stdin);
scanf("%s", roomChoice);
fflush(stdin);
fflush(stdout);
}
void *getTime(void *arg) {
pthread_mutex_lock(&mutex);
FILE *file = fopen("currentTime.txt", "w");
time_t curtime;
struct tm *loc_time;
curtime = time(NULL);
loc_time = localtime(&curtime);
fprintf(file, "%s\n", asctime(loc_time));
// printf("\n%s\n", asctime (loc_time));
fclose(file);
pthread_mutex_unlock(&mutex);
}
void *createRooms() {
// Create directory
int pid = getpid();
char prefix[] = "eldridgt.";
sprintf(directory, "%s%d", prefix, pid);
if (stat(directory, &st) == -1) {
mkdir(directory, 0700);
}
// Create room files
for (i = 0; i < 7; i++) {
int random;
char filePath[100];
int connectionArr[10];
memset(connectionArr, 0, sizeof connectionArr);
random = rand() % 10; // Random number 0-9
if (connectionArr[random] == 0) { // If room not used
sprintf(filePath, "%s/%s", directory, ROOM_NAMES[random]);
FILE *file = fopen(filePath, "ab+");
fprintf(file, "ROOM NAME: %s\n", ROOM_NAMES[random]); // Add room name
fclose(file);
rooms[i] = ROOM_NAMES[random];
connectionArr[random] = 1; // Room has been used
}
}
return rooms;
}
void *createConnections() {
for (i = 0; i < 7; i++) {
int connectionCount = rand() % 4 + 3; // Random number 3-6
int currentCount = 0;
for (j = 0; j < 7; j++) {
currentCount = currentCount + connections[i][j];
}
while (currentCount < connectionCount + 1) {
int random = rand() % 7;
while (random == i) {
random = rand() % 7; // If random == current, reset random
}
// Set connections between both rooms
connections[i][random] = 1;
connections[random][i] = 1;
currentCount++;
}
}
}
void *connectionsToFiles() {
for (i = 0; i < 7; i++) {
int connectionCount = 1;
for (j = 0; j < 7; j++) {
if (connections[i][j] == 1) {
char filePath[100];
sprintf(filePath, "%s/%s", directory, rooms[i]);
FILE *file = fopen(filePath, "ab+");
fprintf(file, "CONNECTION %d: %s\n", connectionCount, rooms[j]);
fclose(file);
connectionCount++;
}
}
}
}
void *roomTypesToFiles() {
for (i = 0; i < 7; i++) {
char filePath[100];
sprintf(filePath, "%s/%s", directory, rooms[i]);
FILE *file = fopen(filePath, "a");
switch (i) {
case 0 :
fprintf(file, "ROOM TYPE: START_ROOM\n");
break;
case 6 :
fprintf(file, "ROOM TYPE: END_ROOM\n");
break;
default :
fprintf(file, "ROOM TYPE: MID_ROOM\n");
}
fclose(file);
}
}
int isEndRoom(int idx) {
movesRecord[totalMoves - 1] = rooms[idx];
char filePath[100];
sprintf(filePath, "%s/%s", directory, rooms[idx]);
char roomType[20];
int lineNumber = 1;
FILE *file = fopen(filePath, "r");
int totaLines = 0;
char line[256];
while (fgets(line, sizeof line, file) != NULL) {
totaLines++; // Line count of room file
}
fclose(file);
file = fopen(filePath, "r");
while (fgets(line, sizeof line, file) != NULL) {
if (lineNumber == totaLines) {
int length = strlen(line) - 11;
strcpy(roomType, line + 11);
roomType[length - 1] = '\0';
}
lineNumber++;
}
// Check if this is the end room
if (strncmp(roomType, "END", 3) == 0) {
printf("YOU HAVE FOUND THE END ROOM. CONGRATULATIONS!\n");
printf("YOU TOOK %d STEPS. YOUR PATH TO VICTORY WAS:\n", totalMoves - 1);
for (i = 1; i < totalMoves; i++) {
printf("%s\n", movesRecord[i]);
}
return 1; // End was reached
} else {
return 0; // End was not reached
}
}
void *playGame(int idx) {
totalMoves++;
printf("\n");
if (isEndRoom(idx)) {
exit(0);
}
while (1) {
char filePath[100];
sprintf(filePath, "%s/%s", directory, rooms[idx]);
FILE *file = fopen(filePath, "r");
int totaLines = 0;
char line[100];
while (fgets(line, sizeof line, file) != NULL) {
totaLines++; // Line count of room file
}
fclose(file);
file = fopen(filePath, "r");
int lineNumber = 0;
char roomChoices[6][20];
while (fgets(line, sizeof line, file) != NULL) { // Current room name
if (lineNumber == 0) {
char roomName[20];
int length = strlen(line) - 11;
strcpy(roomName, line + 11);
roomName[length - 1] = '\0';
printf("CURRENT LOCATION: %s\n", roomName);
} else if (lineNumber == 1) { // First room choice option
printf("POSSIBLE CONNECTIONS: ");
fflush(stdout);
char roomName[20];
int length = strlen(line) - 14;
strcpy(roomName, line + 14);
roomName[length - 1] = '\0';
printf("%s", roomName);
strcpy(roomChoices[lineNumber - 1], roomName);
} else if (lineNumber > 1 && lineNumber < totaLines - 1) { // Subsequent room choice options
printf(", ");
fflush(stdout);
char roomName[20];
int length = strlen(line) - 14;
strcpy(roomName, line + 14);
roomName[length - 1] = '\0';
printf("%s", roomName);
fflush(stdout);
strcpy(roomChoices[lineNumber - 1], roomName);
} else {
printf(".");
fflush(stdout);
}
lineNumber++;
}
fclose(file);
printf("\nWHERE TO? >");
getRoomChoice(); // Get next room choice
if (strcmp(roomChoice, "time") == 0) {
pthread_t thread;
int rc = pthread_create(&thread, NULL, &getTime, NULL);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
pthread_mutex_lock(&mutex);
sleep(1);
FILE *file = fopen("currentTime.txt", "r");
char currentTime[25];
fgets(currentTime, sizeof currentTime, file);
printf("\n%s\n\n", currentTime);
pthread_mutex_unlock(&mutex);
} else {
for (i = 0; i < totaLines - 2; i++) {
if (strcmp(roomChoices[i], roomChoice) == 0) {
for (j = 0; j < 7; j++) {
if (strcmp(rooms[j], roomChoice) == 0) { // If the room is equal to roomChoice
playGame(j); // Make playGame call for new room
}
}
}
}
printf("\nHUH? I DON’T UNDERSTAND THAT ROOM. TRY AGAIN.\n\n");
fflush(stdout);
fflush(stdin);
}
}
}
int main() {
createRooms();
createConnections();
connectionsToFiles();
roomTypesToFiles();
playGame(0);
return 0;
}
Test
rooms
CURRENT LOCATION: Earth
POSSIBLE CONNECTIONS: th, Air, Ice, DarkMatter, Earth, DarkMatter, Earth, Air, DarkMatter, DarkMatter, RT_ROOM.
WHERE TO? >Air
YOU HAVE FOUND THE END ROOM. CONGRATULATIONS!
YOU TOOK 1 STEPS. YOUR PATH TO VICTORY WAS:
Air
Process finished with exit code 0

C free() invalid next size (normal)

I'm fairly new to C and I can't seem to figure out what seems to be a pretty simple pointer problem. My program adds line numbers to a file. It reads in the file line by line and then adds a line number to the beginning of each line. It works fine on each file individually as you can see below:
soccer#soccer-Dell-DV051:~/code C$ ./a.out test.c
soccer#soccer-Dell-DV051:~/code C$ ./a.out miscellaneousHeader.h
soccer#soccer-Dell-DV051:~/code C$ ./a.out test.c miscellaneousHeader.h
*** Error in `./a.out': free(): invalid next size (normal): 0x08648170 ***
Segmentation fault (core dumped)
soccer#soccer-Dell-DV051:~/code C$
but when I run them together I get the above error. The following code is my program.
Compiler.c:
#include <stdio.h>
#include "lineNumAdderHeader.h"
#include "miscellaneousHeader.h"
int main(int argc, char *argv[]){
if (argc < 2)
fatal("in main(). Invalid number of arguments");
int i = 1;
while (i < argc){
lineNumAdder(argv[i]);
i++;
}
}
I have narrowed the problem to the lineNumPtr. The error occurs when lineNumPtr is freed after the second file. If lineNumPtr is not freed, which I know is bad programming, the program works just fine.
lineNumAdder.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "miscellaneousHeader.h"
#include "lineNumAdderHeader.h"
int lineSizeChecker(FILE*, int);
int lineNumChecker(char*);
int fileSizeChecker(FILE*);
void lineNumAdder(char* filename){
int lineSpace, position, lineNumCheckerBoolean, numOfDigits, fileSpace;
int lineNum = 1;
char *lineNumPtr = NULL;
char *numberedFile = NULL;
char *nonNumberedLine = NULL;
char *originalLine = NULL;
FILE *file = errorCheckedFopen(filename, "r+w");
while(1){
position = ftell(file);
if (position == 0){
fileSpace = fileSizeChecker(file);
numberedFile = errorCheckedMalloc(fileSpace);
}
lineSpace = lineSizeChecker(file, position);
if (position == 0)
originalLine = errorCheckedMalloc(lineSpace);
else
originalLine = realloc(originalLine, lineSpace);
if (fgets(originalLine, lineSpace, file) == NULL)
break;
lineNumCheckerBoolean = lineNumChecker(originalLine);
if (lineNumCheckerBoolean == 0){
if (position == 0)
nonNumberedLine = errorCheckedMalloc(lineSpace - 9);
else
nonNumberedLine = realloc(nonNumberedLine, lineSpace - 9);
strcpy(nonNumberedLine, &originalLine[9]);
}
else{
if (position == 0)
nonNumberedLine = errorCheckedMalloc(lineSpace);
else
nonNumberedLine = realloc(nonNumberedLine, lineSpace);
strcpy(nonNumberedLine, originalLine);
fileSpace += 8;
numberedFile = realloc(numberedFile, fileSpace);
}
numOfDigits = intDigitFinder(lineNum);
if (position == 0)
lineNumPtr = errorCheckedMalloc(numOfDigits);
else
lineNumPtr = realloc(lineNumPtr, numOfDigits);
sprintf(lineNumPtr, "%d", lineNum);
strcat(numberedFile, "/*");
strcat(numberedFile, lineNumPtr);
strcat(numberedFile, "*/");
if (lineNum < 10)
strcat(numberedFile, " ");
else if (lineNum >= 10 && lineNum < 100)
strcat(numberedFile, " ");
else if (lineNum >= 100 && lineNum < 1000)
strcat(numberedFile, " ");
else if (lineNum >= 1000 && lineNum < 10000)
strcat(numberedFile, " ");
strcat(numberedFile, nonNumberedLine);
lineNum++;
}
fclose(file);
free(originalLine);
free(nonNumberedLine);
free(lineNumPtr);
free(numberedFile);
}
int lineNumChecker(char *comment){
if (sizeOf(comment) < 8)
return 1;
if (comment[7] == '/' || comment[6] == '/' || comment[5] == '/' || comment[4] == '/')
return 0;
else
return 1;
}
int lineSizeChecker(FILE *file, int position){
int i = 2;
int ch;
while ((ch = fgetc(file)) != '\n' && ch != EOF)
i++;
fseek(file, position, SEEK_SET);
return i;
}
int fileSizeChecker(FILE *file){
int i = 2;
while (fgetc(file) != EOF)
i++;
fseek(file, 0, SEEK_SET);
return i;
}
miscellaneous.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "miscellaneousHeader.h"
void fatal(char*);
int sizeOf(char *data){
int i = 1;
while(data[i-1] != '\n')
i++;
return i;
}
void *errorCheckedMalloc(size_t size){
void *ptr = malloc(size);
if (ptr == NULL)
fatal("in errorCheckedMalloc(). Memory Allocation Failure\n");
else
return ptr;
}
FILE *errorCheckedFopen(char *filename, char *mode){
FILE *file = fopen(filename, mode);
if (file == NULL)
fatal("in errorCheckedFopen(). File Opening Failure\n");
else
return file;
}
void fatal(char *errorMessage){
char* completedErrorMessage = errorCheckedMalloc(sizeOf(errorMessage)+17);
strcpy(completedErrorMessage, "[!!] Fatal Error ");
strcat(completedErrorMessage, errorMessage);
perror(completedErrorMessage);
free(completedErrorMessage);
exit(-1);
}
int intDigitFinder(int num){
int digits = 0;
do {
num /= 10;
digits++;
} while (num != 0);
return digits;
}
void *reMalloc(void *ptr, size_t size){
char buf[strlen(ptr) + 1];
strcpy(buf, ptr);
free(ptr);
ptr = errorCheckedMalloc(size);
if(size >= strlen(buf))
strcpy(ptr, buf);
return ptr;
}
I apologize for the length. This is my first post and I wanted to make sure that I provided enough information for you guys to give me the best answers possible. Thank you for any and all answers. They are much appriciated.
Ok guys, so I have gotten it to work. I have tweaked the lineNumAdder.c file. The program now increases numberedFile's size by the line each time it is read in. Also the error was occuring on the second file because when I would strcat the line number into the malloced area junk was already stored there, so numberedFile would overflow. I have fixed this by using calloc instead of malloc. Thank you to all who gave answers and commented. They all helped tremendously.
Here is the completed lineNumAdder.c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "miscellaneousHeader.h"
#include "lineNumAdderHeader.h"
int lineSizeChecker(FILE*, int);
int lineNumChecker(char*);
int fileSizeChecker(FILE*);
void lineNumAdder(char* filename){
int lineSpace, filePosition, lineNumCheckerBoolean, numOfDigits;
int fileSpace = 0;
int lineNum = 1;
char *lineNumPtr = NULL;
char *numberedFile = NULL;
char *nonNumberedLine = NULL;
char *originalLine = NULL;
FILE *file = errorCheckedFopen(filename, "r+w");
while(1){
filePosition = ftell(file);
lineSpace = lineSizeChecker(file, filePosition);
if (filePosition == 0)
originalLine = calloc(1, lineSpace);
else
originalLine = realloc(originalLine, lineSpace);
if (fgets(originalLine, lineSpace, file) == NULL)
break;
lineNumCheckerBoolean = lineNumChecker(originalLine);
if (lineNumCheckerBoolean == 0){
fileSpace += lineSpace;
if (filePosition == 0){
nonNumberedLine = calloc(1, lineSpace - 8);
numberedFile = calloc(1, fileSpace);
}
else{
nonNumberedLine = realloc(nonNumberedLine, lineSpace - 8);
numberedFile = realloc(numberedFile, fileSpace);
}
strcpy(nonNumberedLine, &originalLine[9]);
}
else{
fileSpace += lineSpace + 9;
if (filePosition == 0){
nonNumberedLine = calloc(1, lineSpace);
numberedFile = calloc(1, fileSpace);
}
else{
nonNumberedLine = realloc(nonNumberedLine, lineSpace);
numberedFile = realloc(numberedFile, fileSpace);
}
strcpy(nonNumberedLine, originalLine);
}
numOfDigits = intDigitFinder(lineNum);
if(filePosition == 0)
lineNumPtr = calloc(1, numOfDigits);
else
lineNumPtr = realloc(lineNumPtr, numOfDigits);
sprintf(lineNumPtr, "%d", lineNum);
strcat(numberedFile, "/*");
strcat(numberedFile, lineNumPtr);
strcat(numberedFile, "*/");
if (lineNum < 10)
strcat(numberedFile, " ");
else if (lineNum >= 10 && lineNum < 100)
strcat(numberedFile, " ");
else if (lineNum >= 100 && lineNum < 1000)
strcat(numberedFile, " ");
else if (lineNum >= 1000 && lineNum < 10000)
strcat(numberedFile, " ");
strcat(numberedFile, nonNumberedLine);
lineNum++;
}
fclose(file);
free(originalLine);
free(nonNumberedLine);
free(lineNumPtr);
free(numberedFile);
}
int lineNumChecker(char *comment){
if (sizeOf(comment) < 8)
return 1;
if (comment[7] == '/' || comment[6] == '/' || comment[5] == '/' || comment[4] == '/')
return 0;
else
return 1;
}
int lineSizeChecker(FILE *file, int position){
int i = 2;
int ch;
while ((ch = fgetc(file)) != '\n' && ch != EOF)
i++;
fseek(file, position, SEEK_SET);
return i;
}
int fileSizeChecker(FILE *file){
int i = 2;
while (fgetc(file) != EOF)
i++;
fseek(file, 0, SEEK_SET);
return i;
}
So, it's difficult to debug this... But at the very least:
int sizeOf(char *data) {
int i = 1;
while(data[i-1] != '\n' && data[i-1] != '\0')
i++;
return i;
}

Create a file or go to line n of that file

I've been working on this C programming assignment and I just can't seem to find out why it is not behaving the way I expect it to be behaving. The program is supposed to run, and there are 3 possible options for commands 0, -n, and n, where n is a positive integer.
When I execute the program, and type 0 as the command (which should create a file if one has not already been created) it just loops back to asking me to enter a command.
The commands -n and n go to the line specified by n and seeks to it. n prints line n, whereas -n prints all lines from n onward until it can no longer read from the text file.
Would greatly appreciate it if somebody could give me a hint or two and steer me in the right direction.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define BUFSIZE 256
#define LINESIZE 1024
int write(FILE *fp);
int grade_validation(int grade);
int id_validation(char studentid[]);
int display(FILE *fp, int cmd);
int display_all(FILE *fp, int cmd);
int main(int argc, char *argv[]) {
if(argc != 2) {
perror("invalid number of args");
return 1;
} else {
FILE *fp;
if((fp = fopen(argv[1], "wb+")) == 0) {
perror("fopen");
return 1;
}
write(fp);
fclose(fp);
}
return 0;
}
int write(FILE* fp) {
int grade;
char studentid[BUFSIZE];
char input[BUFSIZE];
int cmd;
while(1) {
printf("Input 0 to append, n to view, or -n to view all records starting from n.\n");
if(!fgets(input, LINESIZE, stdin)) {
clearerr(stdin);
return 0;
}
if((sscanf(input, "%d", &cmd) == 1)) {
if(cmd == 0) {
if((id_validation(studentid)) != 1 || (grade_validation(&grade) == -1)) {
continue;
}
fprintf(fp, "%s %3d ", studentid, grade);
} else if(cmd > 0) {
display(fp, cmd);
} else if(cmd < 0) {
display_all(fp, cmd);
}
}
}
}
int grade_validation(int grade) {
char input[BUFSIZE];
FILE *fp;
if(grade >= 0 && grade <= 100) {
return 1;
}
if(sscanf(input, "%d", &grade) == 1) {
if((grade_validation(grade)) == 1) {
if(fprintf(fp, "%3d", grade) == 0) {
return 0;
}
printf("Grade recorded successfully.\n");
return 1;
}
}
return 0;
}
int id_validation(char studentid[]) {
char input[BUFSIZE];
FILE *fp;
size_t i = 0;
if(strlen(studentid) == 9) {
for(i = 0; i < 9; i++) {
if(isdigit(studentid[i])) {
return 1;
}
}
}
if(sscanf(input, "%s", studentid) == 1) {
if((id_validation(studentid)) == 1) {
if(fprintf(fp, "%s", studentid) == 0) {
return 0;
}
printf("Student ID recorded successfully.\n");
return 1;
}
}
return 0;
}
int display(FILE *fp, int cmd) {
char studentid[BUFSIZE];
int grade;
if(!fgets(cmd, BUFSIZE, fp)) {
clearerr(stdin);
return 0;
}
fseek(fp, cmd, SEEK_SET);
fprintf(stderr, "%s %3d", studentid, grade);
}
int display_all(FILE *fp, int cmd) {
char studentid[BUFSIZE];
int grade;
if(!fgets(cmd, BUFSIZE, fp)) {
clearerr(stdin);
return 0;
}
fseek(fp, cmd, SEEK_SET);
while((sscanf(studentid, grade, "%s %3d", cmd)) != EOF) {
fprintf(stderr, "%s %3d", studentid, grade);
}
}
You're trying to validate the uninitialized studentid and grade.
Also, you pass &grade to grade_validation, which expects and integer.
This would cause a warning, which should make you figure out something is wrong. Always compile with warnings enabled, and treated as errors (in gcc, -Wall -Werror).

Resources