I've made a queue header file and I've tried to use it with threads.
What I'm doing is making 2 threads, 1 for reading the characters from the code file and entering the characters to the queue and the other thread is trying to print the characters to the console.
The problem is that no characters are being printed to the console and I can't figure out why.
queue.h :
#ifndef QUEUE_INT
#define QUEUE_INT
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct
{
int *elementData;
unsigned int queueSize;
unsigned int capacityIncrement;
unsigned int elementCount;
} Queue;
void queue_initialize(Queue*, unsigned int);
int queue_add(Queue*, int);
void queue_poll(Queue*);
int queue_peek(const Queue*);
void queue_destroy(Queue*);
bool queue_isEmpty(const Queue*);
void queue_setCapacityIncrement(Queue*, unsigned int);
unsigned int queue_getCapacityIncrement(const Queue*);
unsigned int queue_getNumberOfElements(const Queue*);
unsigned int queue_getSize(const Queue*);
void queue_initialize(Queue *p, unsigned int capacityIncrement)
{
p->elementData = NULL;
p->queueSize = 0;
p->capacityIncrement = capacityIncrement;
p->elementCount = 0;
}
int queue_add(Queue *p, int value)
{
if(p->elementCount == p->queueSize)
{
int newQueueSize = p->queueSize + p->capacityIncrement;
void *temp = realloc(p->elementData, sizeof(*p->elementData) * newQueueSize);
if(temp == NULL || newQueueSize == 0)
{
return 1;
}
p->queueSize = newQueueSize;
p->elementData = temp;
}
p->elementData[p->elementCount] = value;
p->elementCount++;
return 0;
}
void queue_poll(Queue *p)
{
if(!queue_isEmpty(p))
{
p->elementCount--;
if(p->queueSize - p->elementCount == p->capacityIncrement / 2 + p->capacityIncrement)
{
int newQueueSize = p->queueSize - p->capacityIncrement;
p->elementData = realloc(p->elementData, sizeof(*p->elementData) * newQueueSize);
p->queueSize = newQueueSize;
}
for(int i = 0; i < p->elementCount; i++)
{
p->elementData[i] = p->elementData[i + 1];
}
}
}
int queue_peek(const Queue *p)
{
if(!queue_isEmpty(p))
{
return p->elementData[0];
}
return 0;
}
void queue_destroy(Queue *p)
{
free(p);
}
bool queue_isEmpty(const Queue *p)
{
return p->elementCount == 0;
}
void queue_setCapacityIncrement(Queue *p, unsigned int capacityIncrement)
{
p->capacityIncrement = capacityIncrement;
}
unsigned int queue_getCapacityIncrement(const Queue *p)
{
return p->capacityIncrement;
}
unsigned int queue_getNumberOfElements(const Queue *p)
{
return p->elementCount;
}
unsigned int queue_getSize(const Queue *p)
{
return p->queueSize;
}
#endif
Code file :
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include <time.h>
#include "queue.h"
bool isFillQueueThreadRunning;
bool isQueueProcessing;
void fillQueueThread(void*);
void popQueueThread(void*);
int main()
{
srand(time(NULL));
Queue q1;
queue_initialize(&q1, 4);
HANDLE hFillQueueThread = (HANDLE)_beginthread(fillQueueThread, 0, (void*)&q1);
HANDLE hPopQueueThread = (HANDLE)_beginthread(fillQueueThread, 0, (void*)&q1);
WaitForSingleObject(hFillQueueThread, 1000 * 300);
WaitForSingleObject(hPopQueueThread, 1000 * 300);
return 0;
}
void fillQueueThread(void *p)
{
isFillQueueThreadRunning = true;
Queue *q = (Queue*)p;
FILE *f = fopen(__FILE__, "r");
int b;
while((b = getc(f)) != EOF)
{
Sleep(rand() % 50);
while(isQueueProcessing)
{
}
isQueueProcessing = true;
if (queue_add(q, b) == 1)
{
break;
}
isQueueProcessing = false;
}
fclose(f);
isFillQueueThreadRunning = false;
}
void popQueueThread(void *p)
{
Queue *q = (Queue*)p;
Sleep(10);
int b;
while(isFillQueueThreadRunning || q->elementCount > 0)
{
while(isQueueProcessing)
{
}
isQueueProcessing = true;
b = queue_peek(q);
queue_poll(q);
putchar(b);
isQueueProcessing = false;
}
}
you _beginthread the fillQueueThread twice.
and
you never initialize isFillQueueThreadRunning reliably. Code may depend on uninitialized variable.
from what I've seen
Your queue implementation is far from thread safe. As Joachim mentioned, please education yourself with thread synchronization primitives. A simple mutex would go a long way here.
See: What is a mutex?
As to your large blocks of spaces, you use the output of queue_peek() unconditionally which can (and will frequently) be NULL.
Do you know that the result of putchar(NULL) is?
Related
I want to perform a simple task working with function pointers in C.
The task is to get an array (from any type, i.e: int / char*), and sum /concatenate each 2 elements in the array.
for the char* type, it works fine, but for the int type, the loop seems to jump each 2 elements in the array (and thus overflow the array):
#define N1 4
#define N2 4
typedef void*(*Fn_Sum)(void*, void*);
typedef void(Fn_Prt)(void*);
int sum_num(int a, int b){
return a + b;
}
char* sum_char(char* a, char* b){
char *result = malloc(strlen(a) + strlen(b) + 1);
if (!result) {
printf("ERROR: malloc failed !\n");
return NULL;
}
strcpy(result, a);
strcat(result, b);
return result;
}
void print_num(int a){
printf("%d", a);
}
void print_string(char* a){
int i = 0;
while (a[i] != '\0') {
printf("%c", a[i]);
i++;
}
}
void PrintSums(void** P, int n, Fn_Sum fsum, Fn_Prt fprt){
for(int i = 0; i < n - 1; i++){
(fprt)(fsum(P[i], P[i+1]));
printf(", ");
}
printf("\n");
}
int main() {
int V[N1] = {1,2,3,4};
char* S[N2] = {"a", "d", "c", "d"};
PrintSums(V, N1, sum_num, print_num);
PrintSums(S, N2, sum_char, print_string);
return 0;
}
expected output is :
3, 5, 7,
ab, bc, cd,
actual outputs:
4, 725939, 4925336,
ad, dc, cd,
Create an abstract interface for iterator over the elements. A draft of such interface could look like this:
struct iterator {
...
};
// ptr - a pointer to beginning of the array
// size - size of one element in the array
void it_init(iterator *t, void *ptr, size_t size);
bool it_eq(iterator *t, iterator *o); // compare iteratores
void it_add(iterator *t, size_t n);
void it_inc(iterator *t);
// return a pointer to the element
void *it_get(iterator *t);
Remember to always pass to user callbacks a context variables. Otherwise users will have to use global variables, which make code messy. Create an abstract interface with destructors and constructors of your summing object. Handle errors properly:
// is passed a pointer to user context
// returns 0 on success
typedef int (*Fn_Sum)(void*, void*);
// is passed a pointer to user context
// returns 0 on success
typedef int (Fn_Prt)(void*);
// returns 0 on success
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx);
After that, implement objects that expose the interface that you want:
struct num { .. };
void num_sum(struct num *t, int el);
void num_print(struct num *t, int el);
// expose interface to PrintSums
// that just calls internal api
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
An example whole program looks like this:
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// iterator
typedef struct iterator {
void *ptr;
size_t size;
} iterator;
void it_init(iterator *t, void *ptr, size_t size) {
*t = (iterator){ ptr, size, };
}
// eq is from test(1) shell command. "eq" means "equal"
bool it_eq(iterator *t, iterator *o) {
return t->ptr == o->ptr;
}
void it_add(iterator *t, size_t n) {
t->ptr = (char*)t->ptr + t->size * n;
}
// increment the iterator
void it_inc(iterator *t) {
it_add(t, 1);
}
// return a pointer to the element
void *it_get(iterator *t) {
return t->ptr;
}
// interface
typedef int (*Fn_Sum)(void*, void*);
typedef int (Fn_Prt)(void*);
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx){
iterator end = it;
it_add(&end, n);
for(; !it_eq(&it, &end); it_inc(&it)) {
int err = fsum(sumctx, it_get(&it));
if (err) return err;
err = fprt(sumctx);
if (err) return err;
printf(", ");
}
printf("\n");
return 0;
}
// num object
struct num {
int sum;
};
void num_init(struct num *t) {
t->sum = 0;
}
void num_sum(struct num *t, int el){
t->sum += el;
}
void num_print(struct num *t){
printf("%d", t->sum);
}
void num_free(struct num *T) {
// nothing, just exists for uniform API
}
// accessors for PrintSums
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
// string object
struct str {
char *str;
};
void str_init(struct str *t) {
t->str = NULL;
}
int str_sum(struct str *t, const char *str) {
const size_t str_len = t->str == NULL ? 0 : strlen(t->str);
void *p = realloc(t->str, str_len + strlen(str) + 1);
if (p == NULL) {
free(t->str);
t->str = NULL;
return -1;
}
t->str = p;
memcpy(t->str + str_len, str, strlen(str) + 1);
return 0;
}
void str_print(struct str *t) {
if (t->str == NULL) {
printf("(nul)");
} else {
printf("%s", t->str);
}
}
void str_free(struct str *t) {
free(t->str);
}
// interface for PrintSums
int str_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct str *t = ctx;
const char **el = el0;
str_sum(t, *el);
return 0;
}
int str_PrintSums_Fn_Prt(void *ctx) {
struct str *t = ctx;
str_print(t);
return 0;
}
// and finally main
int main() {
int err = 0;
int V[] = {1,2,3,4};
iterator numit;
it_init(&numit, V, sizeof(*V));
struct num numsum; // the object that will hold the sum
num_init(&numsum);
err = PrintSums(numit, sizeof(V)/sizeof(*V), num_PrintSums_Fn_Sum, num_PrintSums_Fn_Prt, &numsum);
if (err) abort();
num_free(&numsum);
char *S[] = {"a", "d", "c", "d"};
iterator strit;
it_init(&strit, S, sizeof(*S));
struct str strsum; // the object that will hold the sum of strings
str_init(&strsum);
err = PrintSums(strit, sizeof(S)/sizeof(*S), str_PrintSums_Fn_Sum, str_PrintSums_Fn_Prt, &strsum);
if (err) abort();
str_free(&strsum); // YES! Remember to pick out the trash
}
and outputs on godbolt:
1, 3, 6, 10,
a, ad, adc, adcd,
The pointers to a constructor and destructor of "sum objects" could be passed to PrintSums too. That said one could start thinking about creating a virtual table for all these pointers (ie. one struct with function pointers that are needed for PrintSums...).
So i implemented a hashtable with separate chaining for a struct called Objective, so that i could perform some operations on said Objectives. Currently i have this:
Hashtable.h:
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/*Using separate chaining to store the obejctives*/
typedef struct Objective{
char name [8000];
unsigned long id, duration, deps [9000];
int hasDeps;
}*pObjective;
typedef struct nodehash{ /*Node of list*/
pObjective obj;
struct nodehash*next;
}*link;
void Init(int M);
int search(unsigned long id);
void insert(pObjective o);
void delete(unsigned long id);
link insertBegin(link h, pObjective obj);
int searchList(link h, unsigned long id);
link removeList(link h, unsigned long id);
pObjective searchObj(unsigned long id);
pObjective searchObjAux(link h, unsigned long id);
#endif
Objectives.c:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "OBJECTIVES.h"
/*Checks if all inserted dependencies already exist*/
int existDeps(unsigned long dep[9000]){
int i, count = 0;
for(i = 0; i < 9000; i++){
if(search(dep[i]) != 0)
count++;
}
return count;
}
/ *Adds objective with dependencies*/
void addObj(unsigned long id, char name [8000], unsigned long duration,
unsigned long dep[9000]){
int i;
pObjective obj = malloc(sizeof(pObjective));
obj->id = id;
obj->duration = duration;
obj->hasDeps = 1;
strcpy(name, obj->name);
for(i = 0; i < 9000; i++){
obj->deps[i] = dep[i];
}
if(search(id) != 0)
printf("id already exists\n");
else if(existDeps(dep) != 0)
printf("no such task\n");
else
insert(obj);
free(obj);
}
/*Adds objective with no dependencies*/
void addNoDeps(unsigned long id, char name [8000], unsigned long
duration){
pObjective obj = malloc(sizeof(pObjective));
obj->id = id;
obj->duration = duration;
obj->hasDeps = 1;
strcpy(name, obj->name);
if(search(id) != 0)
printf("id already exists\n");
else
insert(obj);
free(obj);
}
/*Removes objective with no dependencies*/
void removeObj(unsigned long id){
int res = search(id);
pObjective obj = searchObj(id);
if(res == 0)
printf("no such task\n");
else if(obj->hasDeps == 1)
printf("task with dependencies\n");
else
delete(id);
}
Objectives.h:
#ifndef OBJECTIVES_H
#define OBJECTIVES_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "HASHTABLE.h"
/*Functions to work with objectives*/
int existDeps(unsigned long dep[9000]);
void addObj(unsigned long id, char name [8000], unsigned long duration,
unsigned long dep[9000]);
void addNoDeps(unsigned long id, char name [8000], unsigned long
duration);
void removeObj(unsigned long id);
#endif
Hashtable.c:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "HASHTABLE.h"
#define hash(A,B) (A%B) /*Hash function*/
static link *heads;
static int M;
/*Initiates hashtable with size m*/
void Init(int m){
int i;
M = m;
heads = (link*)malloc(M*sizeof(link));
for(i = 0; i < M; i++)
heads[i] = NULL;
}
/*Searches objective with said id*/
int search(unsigned long id){
int i = hash(id, M);
return searchList(heads[i], id);
}
/*Inserts objective into hashtable*/
void insert(pObjective o){
int i = hash(o->id, M);
heads[i] = insertBegin(heads[i], o);
}
/*Deletes objective using it's id*/
void delete(unsigned long id){
int i = hash(id, M);
heads[i] = removeList(heads[i], id);
}
/*Returns objective with said id*/
pObjective searchObj(unsigned long id){
int i = hash(id, M);
return searchObjAux(heads[i], id);
}
/*Inserts objective into list*/
link insertBegin(link h, pObjective obj){
link new = (link)malloc(sizeof(struct nodehash));
new->obj = obj;
new->next = h;
return new;
}
/*Searches objective by id in a list*/
int searchList(link h, unsigned long id){
link t;
int count = 0;
for(t = h; t != NULL; t = t->next){
if(t->obj->id == id)
count++;
}
return count++;
}
/*Removes objective from list*/
link removeList(link h, unsigned long id){
link t, x, z;
for(t = h; t != NULL; t = t->next){
if(t->next->obj->id == id)
x = t;
}
z = x->next;
x->next = z->next;
free(z);
return h;
}
/*Returns objetive from said id from list*/
pObjective searchObjAux(link h, unsigned long id){
link t, x;
for(t = h; t != NULL; t = t->next){
if(t->obj->id == id)
x = t;
}
return x->obj;
}
I'm quick testing the funcions addObj (adds an objective with dependencies) and addNoDeps (adds an objective with no dependencies) on my main:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "OBJECTIVES.h"
int main(){
unsigned long array [1] = {3};
Init(11);
addNoDeps(1, "tarefa1", 20);
addObj(2, "tarefa2", 20, array);
return 0;
}
But i keep getting segmentation fault(core dumped) and i can't figure out why. Is my implementation wrong? Are the functions wrong? I can't get to the problem, can someone help me?
I can't run your code right now so I can't analyze the core dump, but I believe what is happening is that you are trying to access memory that has already been freed. At the end of addNoDeps, you free the pObjective after putting it into the list. Then, when you addObj after, you search the list and check to make sure that the links object associated with it is not null. Specifically this code:
for(t = h; t != NULL; t = t->next){
if(t->obj->id == id)
count++;
You only check to see that the t (links pointer) is not null, but since you freed the previous object, the t->obj pointer is not pointing to initialized memroy. Therefore trying to access it via t->obj->id is accessing uninitialized memory. If you remove the free(obj) at the end of your addNoDeps and addObj functions you should be fine. You may also want to add checks to make sure that t->obj is not null as well. In general segmentation faults are caused by accessing uninitialized memory, so when debugging check for accessing pointers after a free, double frees, and other things. Also learning to use GDB can help a lot in these situations.
Basically I have a struct
typedef struct {
const char *nome;
const char *apelido;
int numero;
} Aluno;
I want to sort this by numero.
For example, Input:
jonhy_james_123
jack_china_111
Output :
jack_china_111
jonhy_james_123
I have sucessfully done this, but instead of one CTRL+Z to break end of file, I
somehow need to do it twice.
Here is the full code:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <string.h>
typedef struct {
const char *nome;
const char *apelido;
int numero;
} Aluno;
Aluno aluno(const char *nome, const char *apelido, int numero)
{
Aluno result;
result.nome = nome;
result.apelido = apelido;
result.numero = numero;
return result;
}
Aluno *Aluno_new (int n)
{
return (Aluno *) malloc (n * sizeof(Aluno));
}
char *str_dup(const char *s)
{
char *result = (char *) malloc(strlen(s) + 1);
strcpy(result, s);
return result;
}
int aluno_read(Aluno *a)
{
int result = 0;
char nome[50];
char apelido[50];
int numero;
while (scanf("%[^_]_%[^_]_%d\n", nome, apelido, &numero) != EOF) {
a[result++] = aluno(str_dup(nome), str_dup(apelido), numero);
}
return result;
}
void aluno_write(Aluno *a, int n)
{
printf("%s_%s_%d\n", a[0].nome, a[0].apelido, a[0].numero);
for (int i = 1; i < n; i++) {
printf("%s_%s_%d\n", a[i].nome, a[i].apelido, a[i].numero);
}
}
int qsort_cmp_numero(Aluno *x, Aluno *y)
{
return (x->numero - y->numero);
}
int cmp_B(Aluno *x, Aluno *y)
{
int result = qsort_cmp_numero(x,y);
return result;
}
int cmp_final2(const void *p, const void *q)
{
return cmp_B((Aluno *) p, (Aluno *) q);
}
void test_sort()
{
Aluno *aluno = Aluno_new(100001);
int n_aluno = aluno_read(aluno);
qsort(aluno, n_aluno, sizeof(Aluno), cmp_final2);
aluno_write(aluno, n_aluno);
}
int main()
{
test_sort();
return 0;
}
While behavior of Ctrl-Z in Windows has some peculiarities, this is secondary at the moment.
The primary problem is that you placed an \n character at the end of your scanf format. By doing so you asked scanf to wait for non-empty input after the "primary" portion of the input is complete.
This by itself will easily result "strange" behaviors of your scanf, like "ignoring" Enter key and such.
What is that \n doing there? Why did you include it in your format string?
There really isnt much I can say here.
Here is my lexer file:
#include <ctype.h>
#include <stdio.h>
#include "vector.h"
enum TokenType
{
tok_let = -1,
tok_iden = -2,
tok_int = -3,
tok_end = -4
};
typedef struct
{
int type;
char* str_d;
int int_d;
} Token;
char* seed;
int i=0;
char next_char()
{
i++;
return seed[i-1];
}
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
seed = in;
char tap;
if(isalpha(tap = next_char()))
{
char* iden_str="";
iden_str += tap;
char nc;
while(isalnum((nc = next_char())))
iden_str += nc;
if(iden_str == "let")
{
Token* tp;
tp->type = tok_let;
vector_push(toks, (void*)tp);
goto out;
}
Token* tp;
tp->type = tok_iden;
tp->str_d = iden_str;
vector_push(toks, (void*)tp);
}
out:
return toks;
}
int main()
{
vector* toks;
toks = get_tokens("let");
Token* ftok = (Token*)vector_get(toks, 0);
switch(ftok->type)
{
case tok_let:
printf("Its a let\n");
break;
default:
printf("Ummm lol nup\n");
break;
}
}
And here is my vector file:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct d_vector
{
void **items;
int capacity;
int total;
} vector;
void vector_new(vector *v)
{
v->capacity = 4;
v->total = 0;
v->items = malloc(sizeof(void*)*v->capacity);
}
int vector_total(vector *v)
{
return v->total;
}
static void vector_resize(vector *v, int capacity)
{
void** items = realloc(v->items, sizeof(void*) * capacity);
if(items)
{
v->items = items;
v->capacity = capacity;
}
}
void vector_push(vector *v, void* item)
{
if(v->capacity == v->total)
vector_resize(v, v->capacity * 2);
v->items[v->total++] = item;
}
void vector_set(vector *v, int index, void* item)
{
if(index >= 0 && index < v->total)
v->items[index] = item;
}
void* vector_get(vector *v, int index)
{
if(index >= 0 && index < v->total)
return v->items[index];
return NULL;
}
void vector_remove(vector *v, int index)
{
if(index < 0 || index >= v->total)
return;
v->items[index] = NULL;
for (int i = 0; i < v->total - 1; i++) {
v->items[i] = v->items[i + 1];
v->items[i + 1] = NULL;
}
v->total--;
if (v->total > 0 && v->total == v->capacity / 4)
vector_resize(v, v->capacity / 2);
}
void vector_free(vector *v)
{
free(v->items);
}
When I run the code above, I get a Seg-Fault.
How can this be happening? Here is the output of gdb:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400656 in vector_new (v=0x1) at vector.h:14
14 v->capacity = 4;
As you can see, its segfaulting when i set the vector capacity!
But why?
It segfaults because you dereference a garbage pointer:
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
The variable toks is not assigned to anything meaningful, just whatever garbage value happens to be floating about. This gets passed into vector_new() which immediately dereferences it:
void vector_new(vector *v)
{
v->capacity = 4;
Then BAM! it blows up because v points nowhere appropriate.
Try mallocing a vector before making your call to vector_new() or put the malloc in vector_new() and have it return the pointer to the new vector instead. It's also a good idea to check the return value from malloc().
You might try something like:
vector *vector_new(void)
{
vector *v;
if ( (v = malloc(sizeof(*v))) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
v->capacity = 4;
v->total = 0;
if ( (v->items = malloc(sizeof(*v->items)*v->capacity)) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
return v;
}
Then change how you call it:
vector* get_tokens(char* in)
{
vector *toks;
toks = vector_new();
And for every malloc(), let there be a free(). Don't forget to clean up this allocation too or you'll leak memory:
void vector_free(vector *v)
{
free(v->items);
free(v);
}
(You defined a vector_free(), but never called it. You might want to consider doing that too.)
invalid pointer dereference happened
vector *toks;
vector_new(toks);
Should be
vector *toks = (vector*)malloc(sizeof(vector));
vector_new(toks);
I wonder if I'm doing something wrong in my program.
I manage to create a HashTable but when I send it through parameter to my displayingList() function, it crashes.
source.c (contains my functions):
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <math.h>
#include "header.h"
#define MAX 255
int countLetters(char myStr[])
{
int myLen = strlen(myStr), i;
int wordLen = 0;
for (i = 0 ; i < myLen; ++i)
{
wordLen += (int)(myStr[i]);
}
return (wordLen%256);
}
void populateList(NodeT *T[255], char myStr[])
{
NodeT *p, *q;
p = (NodeT *)malloc(sizeof(NodeT));
strcpy (p->key, myStr);
int myPos = countLetters(myStr);
if(T[myPos] == NULL)
{
p->next = NULL;
T[myPos] = p;
}
else
{
q = T[myPos];
p->next = q;
T[myPos] = p;
}
}
void displayList(NodeT *T[255])
{
int i;
NodeT *p;
for(i = 0 ; i < 255; ++i)
{
if(T[i] != NULL)
{
printf("Index: %d - Data:", i);
p = T[i];
while(p != 0)
{
printf("%s, ", p->key); // HERE IT CRASHES.
p = p->next;
}
printf("\n");
}
}
}
main.c (contains the int main()):
#include <stdio.h>
#include <stdlib.h>
#include "header.h"
int main(void)
{
NodeT *T[255];
int n, i;
printf("Give no. of elements:");
scanf("%d", &n);
fflush(stdin);
for(i = 0 ; i < n ; ++i)
{
char name[100];
gets(name);
populateList(T, name);
}
displayList(T);
return 0;
}
header.h (and my header):
#ifndef HEADER_H
#define HEADER_H
typedef struct cell
{
char key[100];
struct cell *next;
}NodeT;
int countLetters(char myStr[]);
void populateList(NodeT *T[], char myStr[]);
void displayList(NodeT *T[]);
#endif // HEADER_H
I tried to see what exactly happens with debugger and it seems that when I send T[] list to displayList() function, actually it doesn't have the same structure as it has in main.c.
ISSUE: the insertion works fine, but when I try to display my list (on each index) it crashes.
Any ideas?
Thanks in advance.
The possible solution is to declare the NodeT *T[255] global. However it isn't the best practice at all.