Output changes in every run reading from file - c

I'm writing a small application for college that parses some wikipedia pages and outputs information about the people in the pages.
I wrote it in Java and am trying to re-write it in C. I'm getting a weird bug, sometimes the program's output is correct and sometimes it is wrong, without changing the input.
Here is a sample input that triggers the error with the name "105.html"
This is the output I get sometimes:
105 Linus Pauling Estadunidense 28 de fevereiro de 1901 Portland, Oregon 19 de agosto de 1994 Big Sur, Califórnia 93
This is the output I get other times:
105 Linus Pauling Estadunidense 28 de f#evereir#o�y� dC�L��e ���y�19I�L��01 Portland, Oregon 19 de agosto de 1994 Big Sur, Califórnia 93
I notice that if I set a breakpoint in XCode, I usually get the RIGHT result...
I'm new to C so I actually have no clue how to start debugging this.
Here is the code if anyone is interested in actually reading it. The code is in a mixture of Portuguese and English but I added English comments so it should be easy to follow.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct pessoa{
int id;
char *nome; //name
char *nacionalidade; // nationality
char *nascimento; // date of birth
char *local_nascimento; // place of birth
char *morte; // date of death
char *local_morte; // place of death
int idade; // age
};
struct pessoa *inicializar(int n) {
struct pessoa *pessoas = malloc(sizeof(pessoas) * n);
return pessoas;
}
void imprimir_pessoa(struct pessoa *p) {
printf("%i %s %s %s %s %s %s %i\n", p->id, p->nome, p->nacionalidade,
p->nascimento, p->local_nascimento, p->morte,
p->local_morte, p->idade);
}
void imprimir_pessoa_asterisco(struct pessoa *p) {
printf("%i ## %s ## %s ## %s ## %s ## %s ## %s ## %i\n", p->id, p->nome, p->nacionalidade,
p->nascimento, p->local_nascimento, p->morte,
p->local_morte, p->idade);
}
size_t index_of(char *string, char *to_find) {
return strstr(string, to_find) - string;
}
char *remove_tags(char *string) {
// inicializa para o mesmo tamanho da string de entrada para garantir que ira caber
char * resp = malloc(sizeof(char) * strlen(string) + 1);
// jumps over the html tags and finds the aproppriate information
for (size_t i = 0; i < strlen(string); i++) {
while (i < strlen(string) && string[i] == '<') {
for (i++; string[i] != '>'; i++);
i++;
while(i < strlen(string) && string[i] == '&'){
for (i++; string[i] != ';'; i++);
i++;
}
}
while(i < strlen(string) && string[i] == '&'){
for (i++; string[i] != ';'; i++);
i++;
resp[strlen(resp)] = ' ';
}
if (i < strlen(string)) {
resp[strlen(resp)] = string[i];
}
}
while(strlen(string) > 0 && resp[0] == ' '){ // jumps over white spaces on the begining
resp += 1;
}
resp[strlen(resp)] = 0;
return resp;
}
char* extrair_nome(char *string) { // extract the person's name
size_t index = index_of(string, "<title>") + strlen("<title>");
size_t index_fim = index_of(string, " Wiki") - 4;
char *nome = malloc(sizeof(char) * (index_fim - index));
memcpy(nome, (string+index), index_fim - index);
return nome;
}
char* substring(char * string, char *c) {
return string + strcspn(string, c);
}
void remove_new_line(char *string) {
char *pos;
if ((pos=strchr(string, '\n')) != NULL)
*pos = '\0';
}
void ler_pessoa(char *nome_arquivo, struct pessoa *p) { // parse the file to fill the pessoa struct
size_t length = strlen(nome_arquivo);
p->id = (nome_arquivo[length - 8] - 48) * 100;
p->id = (p->id + (nome_arquivo[length - 7] - 48) * 10);
p->id = p->id + (nome_arquivo[length - 6] - 48);
int tamanho_linha = 2000;
char *linha = malloc(sizeof(char) * tamanho_linha);
FILE *fp = fopen(nome_arquivo, "r");
if (fp == NULL) {
printf("Falha ao abrir arquivo %s\n", nome_arquivo);
exit(1);
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "<title>")) { // extracts name
p->nome = extrair_nome(linha);
remove_new_line(p->nome);
break;
}
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Nacionalidade")) { // extracts nationality
fgets(linha, tamanho_linha, fp);
p->nacionalidade = remove_tags(linha);
remove_new_line(p->nacionalidade);
break;
}
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Nascimento")) { // extracts date of births
fgets(linha, tamanho_linha, fp);
p->nascimento = remove_tags(linha); // <-- this one is not working all the time??
remove_new_line(p->nascimento);
break;
}
}
//se vivo
if (strstr(p->nascimento, ")") != NULL) { // if the person is alive the date of birth date is of the type: date(age)
char *tmp = malloc(sizeof(char) * strlen(p->nascimento)); // so we extract the age
strcpy(tmp, p->nascimento);
tmp = tmp + strcspn(tmp, "(") + 1;
tmp[index_of(tmp, " ")] = 0;
p->idade = atoi(tmp);
p->morte = "vivo"; // not dead
p->local_morte = "vivo"; // not dead
} else {
p->morte = ""; // we set this later
p->local_morte = "";
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Local")) { // extracts place of death
fgets(linha, tamanho_linha, fp);
p->local_nascimento = remove_tags(linha);
remove_new_line(p->local_nascimento);
break;
}
}
if (strlen(p->morte) == 0) { // we set this now if the person is not alive (hence size 0)
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Morte")) { // extract death day
fgets(linha, tamanho_linha, fp);
p->morte = remove_tags(linha);
remove_new_line(p->morte);
break;
}
}
if (strstr(p->morte, "(") != NULL) {
char *tmp = malloc(sizeof(char) * strlen(p->morte));
strcpy(tmp, p->morte); // extract age when the person died, like above
tmp = tmp + strcspn(tmp, "(") + 1;
tmp[index_of(tmp, " ")] = 0;
p->idade = atoi(tmp);
p->morte[index_of(p->morte, "(")] = 0;
}
while (fgets(linha, tamanho_linha, fp) != NULL) {
if (strstr(linha, "Local")) { // get the place of death
fgets(linha, tamanho_linha, fp);
p->local_morte = remove_tags(linha);
remove_new_line(p->local_morte);
break;
}
}
}
fclose(fp);
}
int main(int argc, const char * argv[]) {
struct pessoa p;
ler_pessoa("/tmp/105.html", &p);
imprimir_pessoa(&p);
return 0;
}

resp[strlen(resp)] = ' '; and resp[strlen(resp)] = string[i]; are bad as resp[] is not certainly null character terminated.
Code needs a new approach to determine which element of resp[] to assign.
resp[strlen(resp)] = 0; is questionable too.
strlen(resp) returns the length of the string, not counting the null terminator. For strlen() to work well, resp must be null terminated first, else it is not referencing a string. The null character is in the index that equals the length, so resp[strlen(resp)] = 0; is a no-op function, other than killing some CPU cycles.
Code has other problems.
Example: Insufficient space. #Weather Vane;
// bad code
char *tmp = malloc(sizeof(char) * strlen(p->nascimento)); // so we extract the age
strcpy(tmp, p->nascimento);
Sample string allocator/duplicator (Note: strdup() often exists on many platforms)
char *strdupe(const char *s) {
size_t size = strlen(s) + 1;
dupe = malloc(size);
if (dupe) {
memcpy(dupe, s, size);
}
return dupe;
}

Related

C program in CLion runs perfectly in Debug mode but returns exit code -1073741819 (0xC0000005) when executed normally

I am doing the Advent of Code, and I am trying to do it all in C. I am currently on day three, and I kind of solved it, but as the title says it behaves very strangely in my IDE CLion. Here is the objective.
I would very much like to know why it is not running properly, and finding out why appears to be beyond my capability.
This is my code:
//
// Created by gusta on 2022-12-06.
//
#include "aocio.h"
#include <string.h>
int cexists(char* cp, char c, int length);
char getDuplicate(char* line);
int main() {
FILE* fptr = openFile("../Inputs/day3.txt");
char* line;
while (readLine(fptr, &line)) {
char c = getDuplicate(line);
putchar(c);
}
return 0;
}
char getDuplicate(char* line) { // Returnerar STRING_END om ingen fanns
unsigned int length = strlen(line);
char letters[length/2];
char* cp = &letters[0];
for (int i = 0; i < length/2; i++) {
letters[i] = ' ';
}
for (int index = 0; line[index] != STRING_END; index++) {
if (index < length/2) {
int i_char = cexists(letters, line[index], length/2);
if (i_char == -1) {
*cp = line[index];
cp++;
}
}
else {
if (cexists(letters, line[index], length/2) != -1) {
return line[index];
}
}
}
}
int cexists(char* cp, char c, int length) {
for (int i = 0; i < length; i++) {
if (cp[i] == c) {
return i;
}
}
return -1;
}
Here is aocoi.h (advent of code input output.h):
//
// Created by gusta on 2022-12-01.
//
#ifndef ADVENTOFCODE_AOCIO_H
#define ADVENTOFCODE_AOCIO_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define SIGN_ASCII 45
#define TRUE 1
#define FALSE 0
#endif //ADVENTOFCODE_AOCIO_H
#define STRING_END '\0'
#define NUMBERS_ASCII 48
char* prompt(const char* question) {
printf(question);
char* string = malloc(1);
int curChar = 0, index = 0;
while (curChar != '\n') {
curChar = getchar();
if (curChar == '\n'){
string[index] = STRING_END;
}
else{
if (index > 0) {
string = (char*) realloc(string, index+1);
}
string[index] = curChar;
}
index++;
}
return string;
}
FILE* openFile(const char* fileName) {
FILE *fptr;
fptr = fopen(fileName, "r");
if (fptr == NULL) {
printf("Big fat file error!!\n");
fclose(fptr);
getchar();
exit(-1);
}
return fptr;
}
char readLine(FILE* fptr, char** line) {
int index = 0, end = 0;
char* string = (char *) malloc(1);
char curChar;
do {
end = fscanf(fptr, "%c", &curChar);
if (end == EOF) {
string[index] = STRING_END;
fclose(fptr);
*line = string;
return FALSE;
}
if (curChar == '\n') {
string[index] = STRING_END;
*line = string;
return TRUE;
}
else {
if (index > 0) {
string = (char *) realloc(string, index + 1);
}
string[index] = curChar;
index++;
}
} while (end != EOF);
}
int parseToInt(char* string) {
int numberLength = 0, number = 0;
int sign = FALSE;
for (int index = 0; string[index] != STRING_END; index++) {
numberLength++;
}
for (int index = numberLength-1; index >= 0; index--) {
char curChar = string[index];
if (index == 0 && curChar - SIGN_ASCII == 0) {
sign = TRUE;
continue;
}
if (curChar - NUMBERS_ASCII >= 0 && curChar - NUMBERS_ASCII <= 9) {
int num = (int) (curChar - NUMBERS_ASCII);
num *= (int)(pow(10, numberLength-index-1));
number += num;
}
else {
printf("Felaktig inmatning. parseInt kan bara ta in tal"); // Invalid input. parseInt can only take in numbers
getchar();
exit(-1);
}
}
if (sign == TRUE) {
number *= -1;
}
return number;
}
Through searching the web I found that the error code should mean stack overflow (ha!) or something like that, but I cannot for the life of me find any place in my code where that could occur. All pointers and stuff should be automatically freed - is there something I have missed?
In readLine():
if (index > 0) {
string = (char *) realloc(string, index + 1);
}
string[index] = curChar;
After this section, the buffer has size index+1, therefore string[index] is the last element you can write to. Afterwards, you do
index++;
Now, writing to string[index] is out of bounds, resulting in a buffer overflow. This is what happens when an EOF or EOL is detected.

Why doesn't this program print the name?

I’m trying to make a program that receives a text from a file where its lines are a first name, a last name and a note. I want to return the ordered lines: first the students with a grade lower than 5 and after the students passed in order of appearance in the file. The problem is that I can’t print the names and I don’t know what the fault is. The main code is as follows:
int main(int argc, char *argv[])
{
char line[MaxLinea+1];
char *name;
char *surname;
lista_notas *mi_lista = NULL;
int i, blank, grade;
FILE *archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade < 5) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
fclose(archivo);
archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade > 4) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
mostrar_lista(mi_lista);
free_lista(mi_lista);
//system("leaks a.out");
return 0;
}
The get_name function is:
char *get_name(char *line)
{
int i;
char *name = malloc(51);
if (name == NULL)
exit(71);
i = 0;
while(line[i] != ' ')
name[i] = line[i++];
name[i] = 0;
return name;
}
If the program receives a fich.txt which content is:
Nombre1 Apellido1 8
Nombre2 Apellido2 2
Nombre3 Apellido3 6
The output must be:
Nombre2 Apellido2 2
Nombre1 Apellido1 8
Nombre3 Apellido3 6
but instead, it is:
Apellido2 2
Apellido1 8
Apellido3 6
Thanks for your help!
The full code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxLinea 154
//Tamaño máximo linea = 50 (nombre) + 100 (apellido) + 2 (nota máx 10)
// + 2 espacios + caracter nulo? = 155
typedef struct notas{
char *nombre;
char *apellido;
int nota;
struct notas *siguiente;
} lista_notas;
int get_grade(char *line);
char *get_name(char *line);
char *get_surname(char *line);
void insertar(lista_notas **ptr, char *name, char *surname, int grade);
void mostrar_lista(lista_notas *ptr);
void free_lista(lista_notas *ptr);
int main(int argc, char *argv[])
{
char line[MaxLinea+1];
char *name;
char *surname;
lista_notas *mi_lista = NULL;
int i, blank, grade;
FILE *archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade < 5) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
fclose(archivo);
archivo = fopen(argv[1], "r");
while(fgets(line, MaxLinea, archivo)) //recorrer linea fich
{
grade = get_grade(line);
if (grade > 4) //Insertar en la lista
{
name = get_name(line);
surname = get_surname(line);
insertar(&mi_lista, name, surname, grade);
}
}
mostrar_lista(mi_lista);
free_lista(mi_lista);
//system("leaks a.out");
return 0;
}
void insertar(lista_notas **ptr, char *name, char *surname, int grade)
{
lista_notas *p1, *p2;
p1 = *ptr;
if(p1 == NULL)
{
p1 = malloc(sizeof(lista_notas));//y si usamos calloc ¿qué cambia?
if (p1 == NULL)
exit(71);
if (p1 != NULL)
{
p1->nombre = name;
p1->apellido = surname;
p1->nota = grade;
p1->siguiente = NULL;
*ptr = p1;
}
}
else
{
while(p1->siguiente != NULL)//recorrer la lista hasta el último
p1 = p1->siguiente;
p2 = malloc(sizeof(lista_notas));//y si usamos calloc ¿qué cambia?
if (p2 == NULL)
exit(71);
if(p2 != NULL)
{
p2->nombre = name;
p2->apellido = surname;
p2->nota = grade;
p2->siguiente = NULL;
p1->siguiente = p2;
}
}
}
void mostrar_lista(lista_notas *ptr)
{
while(ptr != NULL)
{
printf("%s ",ptr->nombre);
printf("%s ",ptr->apellido);
printf("%d\n",ptr->nota);
ptr = ptr->siguiente;
}
/* printf("\n");*/
}
void free_lista(lista_notas *ptr)
{
lista_notas *aux = ptr;
lista_notas *aux2;
while(aux != NULL)
{
aux2 = aux;
aux = aux->siguiente;
free(aux2->nombre);
free(aux2->apellido);
free(aux2);
}
}
int get_grade(char *line)
{
int i, blank, num;
i = 0;
blank = 0;
while(line[i] != '\0')
{
if (blank == 2) //sacar la nota
{
num = atoi(&line[i]);
blank++;
}
else if(line[i] == ' ')
blank++;
i++;
}
return num;
}
char *get_name(char *line)
{
int i;
char *name = malloc(51);
if (name == NULL)
exit(71);
i = 0;
while(line[i] != ' ')
name[i] = line[i++];
name[i] = 0;
return name;
}
char *get_surname(char *line)
{
int i, j;
char *surname = malloc(101);
if (surname == NULL)
exit(71);
i = 0;
j = 0;
while(line[i] != ' ')
i++;
while(line[++i] != ' ')
surname[j++] = line[i];
surname[j] = 0;
return surname;
}
At least these problems:
++ not sequenced
name[i] = line[i++]; is bad code. The i++may occur before, after, (or even during) name[i]. Result: undefined behavior (UB). #paddy
Limited size
char *name = malloc(51); does not need to use the magic number 51.
May run off end
while(line[i] != ' ') leads to trouble when line[] lacks a ' '.
Alternative (like OP's code)
char *get_name(char *line) {
size_t i = 0;
while(line[i] != ' ' && line[i] != '\0') {
i++;
}
char *name = malloc(i + 1);
if (name == NULL) {
exit(71);
}
for (size_t j = 0; j < i; j++) {
name[j] = line[j];
}
name[i] = 0;
return name;
}
Or perhaps using standard efficient library functions
char *get_name(const char *line) {
size_t token_length = strcspn(line, " ");
char *name = malloc(token_length + 1);
if (name == NULL) {
exit(71); // Consider a named macro/enum here rather than a magic 71
}
name[token_length] = '\0';
return memcpy(name, line, token_length);
}
Other issues
Off by 1
// fgets(line, MaxLinea, archivo)
fgets(line, sizeof line, archivo)
Advanced: Assuming first, last names do not include spaces
Consider first names like "Betty Jo" and last names like Lloyd Webber
Some names are longer than 51.

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;
}

reading a text file and sort it in a new file

I have a school assignment in which we have to read a text file, sort the words by alphabetical order and write the result into a new text file.
I've already got a program that can read the file and print it on the screen and a different program to sort words which you have to type in. Now I'm trying to merge these two programs, so that the data which been read out of the file will be put into the sorting program.
The program that we use to make the code is called CodeBlocks. Below are the two programs. I hope that you can give me advice and an example how to fix this because I tried everything I know but couldn't get it working.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#define MAX_NUMBER_WORDS 100
char* ReadFile(char *filename)
{
char *buffer = NULL;
int string_size, read_size;
FILE *handler = fopen(filename, "r");
if (handler)
{
//seek the last byte of the file
fseek(handler, 0, SEEK_END);
//offset from the first to the last byte, or in other words, filesize
string_size = ftell(handler);
//go back to the start of the file
rewind(handler);
//allocate a string that can hold it all
buffer = (char*)malloc(sizeof(char) * (string_size + 1));
//read it all in one operation
read_size = fread(buffer, sizeof(char), string_size, handler);
//fread doesnt set it so put a \0 in the last position
//and buffer is now officialy a string
buffer[string_size] = '\0';
if (string_size != read_size)
{
//something went wrong, throw away the memory and set
//the buffer to NULL
free(buffer);
buffer = NULL;
}
}
return buffer;
}
int numberOfWordsInDict(char **dict)
{
int i;
for (i = 0; i < MAX_NUMBER_WORDS; i++)
{
if (dict[i] == NULL)
return i;
}
return MAX_NUMBER_WORDS;
}
void printDict(char **dict)
{
int i;
printf("Dictionary:\n");
for (i = 0; i < numberOfWordsInDict(dict); i++)
printf("- %s\n", dict[i]);
if (numberOfWordsInDict(dict) == 0)
printf("The dictionary is empty.\n");
}
void swapWords(char **dict, char *word, char *word2)
{
int i, p1 = -1, p2 = -1;
char *tmp;
for (i = 0; i < numberOfWordsInDict(dict); i++)
{
if (strcmp(dict[i], word) == 0)
p1 = i;
if (strcmp(dict[i], word2) == 0)
p2 = i;
}
if (p1 != -1 && p2 != -1)
{
tmp = dict[p1];
dict[p1] = dict[p2];
dict[p2] = tmp;
}
}
void sortDict(char **dict)
{
int swap;
int i = 0;
do
{
swap = 0;
for (i = 0; i < numberOfWordsInDict(dict) - 1; i++)
{
if (strcmp(dict[i], dict[i + 1]) > 0)
{
swapWords(dict, dict[i], dict[i + 1]);
swap = 1;
}
}
} while (swap == 1);
}
void splitSentenceToWords(char **words, char *sentence)
{
int p1 = 0, p2 = 0;
int nrwords = 0;
char *word;
while (sentence[p2] != '\0')
{
if (isspace(sentence[p2]) && p1 != p2)
{
word = (char*)malloc(sizeof(char)*(p2 - p1 + 1));
words[nrwords] = word;
strncpy(words[nrwords], &sentence[p1], p2 - p1);
words[nrwords][p2 - p1] = '\0';
nrwords++;
p1 = p2 + 1;
p2 = p1;
}
else
{
p2++;
}
}
if (p1 != p2)
{
word = (char*)malloc(sizeof(char)*(p2 - p1 + 1));
words[nrwords] = word;
strncpy(words[nrwords], &sentence[p1], p2 - p1);
words[nrwords][p2 - p1] = '\0';
nrwords++;
p1 = p2 + 1;
p2 = p1;
}
}
int main(void)
{
char sentence[1024];
char *dict[MAX_NUMBER_WORDS] = {};
char *words[MAX_NUMBER_WORDS] = {};
char *string = ReadFile("test.txt");
if (string)
{
puts(string);
free(string);
}
//printf("Type een zin in: ");
scanf("%[^\n]s", &sentence);
splitSentenceToWords(words, &sentence);
printDict(words);
printf("Words has been sorted\n");
sortDict(words);
printDict(words);
return 0;
}
You are on the right track. The problem is that after your read in your file, you are not using the input to build your word list. Instead of;
splitSentenceToWords(words, &sentence);
try:
splitSentenceToWords(words, &string);
Delete
free(string)
This will get you started. You will have to clean this up when you understand it a bit better.

C pointers in linked list [closed]

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;
}

Resources