I use this structure for my tree:
typedef struct product{
char name[50];
char id[5];
double price;
int amount;
struct product *left_p, *right_p;
}product_t;
So, I must convert the tree into an array.
I wrote this for the tree dimension:
int tree_dim(product_t *node_p){
int i = 1 ;
if (node_p == NULL)
i = 0;
else{
i += tree_dim(node_p->left_p);
i += tree_dim(node_p->right_p);
}
return i;
}
My tree is populated by reading the records from a txt file. The records are 21 and the value returned by tree_dim is correct. The value is stored inarr_dim.
Then I create aproduct_t *products_a; wich will be the "array" and allocate it in memory by using products_a = malloc (arr_dim*sizeof (product_t));
Now, this is the function to fill the array with the tree nodes:
void fill_array(int *index, product_t *node_p, product_t *products_a){
if (node_p != NULL){
fill_array(index, node_p->left_p, products_a);
products_a[*index++] = *node_p;
fill_array(index, node_p->right_p, products_a);
}
}
But it gives me segmentation fault error so I also tried this 2nd solution:
int fill_array(product_t *node_p, product_t *products_a){
int i = 1 ;
if (node_p == NULL){
i=0;
}
else
{
i += fill_array(node_p->left_p, products_a);
products_a[i-1] = *node_p;
i += fill_array(node_p->right_p, products_a);
}
return i;
}
Which doesn't give segmentation fault but when I print the array there are empty positions.
I need some tips on where I'm wrong. Maybe a problem with the index and the recursive calls but I can't figure it out.
Look at the precedence of these two operators
*index++
++ Incrementation has higher precedence than * dereference right?
So if you first move in memory by sizeof(int) then you arent no more in your allocated memory and dereferencing would cause UB.
Its always better to use brackets () if you arent sure about precedence.
(*index)++ // This is right
Filip has already pointed out the problem with your first function.
The problem with your second function is that it works only when filling from the left branch. After you have done that and copied the current product, there are some elements in the array, but copying from the right branch will start at index 0 again, so it will overwrite existing data and leave data at the end uninitialised.
You could fix this by passing the current index i to your function, but I find the i = func(..., i); syntax a bit redundant.
In C, you can pass in a subarray of array starting at element i with &array[i] or just array + i. (Remember that an array in a function call "decays" into a pointer to the first element, &array[0].)
So this will work:
int fill_array(product_t *node_p, product_t *products_a)
{
int i = 0;
if (node_p == NULL) return 0;
i += fill_array(node_p->left_p, products_a);
products_a[i++] = *node_p;
i += fill_array(node_p->right_p, &products_a[i]);
return i;
}
Related
My original code to display nodes in a queue in order from lowest to greatest:
void display (queue *q) {
node *ptr = q->front;
int i = 0;
int size = q->size;
while (i <= size) {
while (ptr->id != i) {
ptr = ptr->next;
}
if (i == 0) {
printf("%d ", ptr->id);
printf("%d\n", ptr->running);
}
else {
printf("%d ", ptr->id);
}
i++;
ptr = q->front;
}
}
Had kept producing Segmentation Fault (Core Dumped) errors. I have malloc the two variables being compared and this error has been fixed.
void display (queue *q) {
node *ptr = malloc(10);
ptr = q->front;
int *i = NULL;
i = malloc(sizeof(int));
*i = 0;
int size = q->size;
while(*i <= size){
while (ptr->id != *i) {
ptr = ptr->next;
}
if (*i == 0) {
printf("%d %d\n", ptr->id, ptr->running);
}
else {
printf("%d %d %d %d\n", ptr->id, ptr->running, ptr->ready, ptr->blocked);
}
i = i + 1 * (sizeof(char));
ptr = q->front;
}
}
However now this doesn't produce the output that I want. I want to increment the i pointer so that it can be the same as my original code.
This has been immensely frustrating, any help would be greatly appreciated!
If I read your first code listing correctly, there's at least one important thing here you need to think about. You seem to have a linked list here, and you're iterating over that list using ptr = ptr->next. This means you need to know when to stop. One common way of setting up a linked list is that the last item in the list has a next value of NULL. Then process the nodes one at a time, and once you are done with one node, you you check whether the next value is NULL: if it isn't you can move on that that next node, if it is NULL you stop.
Here you're not doing checks like this, so you need another way to ensure that you know when to stop. What you seem to be doing is taking the value of q->size and using that to inform you how many items there are in the linked list. So the first thing to think about is how confident you are that that value is correct. For example, if the code building the list puts only two items into the list, bet sets size to three, you'll end up falling off the end of the list, and a segmentation fault is not unlikely.
But there's something even more important than that. Even if you're getting the correct number of items in the list from q->size, you're comparing your loop variable i to size like this:
int i = 0;
while (i <= size) {
⋮
}
This is going to loop with i having the values [ 0, 1, … size ], which is actually size + 1 times. If you want to loop exactly size times, you want a test like i < size rather than i <= size. This is a common mistake, often called an off-by-one error.
Unfortunately, your second listing complicates things, rather than making them better. Go back to your first one and see if you can fix the things I've mentioned here.
I have been building this hash table function that is given an array it gets a word from and a pointer to an array that it fills with my linked list struct. It compiles correctly but I get a segmentation fault at - *hashTable[hashVal] = *newNode; .
void hashTableCreate(char *array, list *hashTable[]) {
while(arrayPos < getArrayLength(array)) {
char *temp = getWord(array);
int hashVal = hashingFunc(temp);
if((*hashTable[hashVal]).word == temp ) {
(*hashTable[hashVal]).count = (*hashTable[hashVal]).count+1;
}
else {
list *newNode = malloc(sizeof(list));
strcpy(newNode->word,temp);
newNode->count = 1;
*hashTable[hashVal] = *newNode;
}
}
}
It's called like this:
void timeStructures(char *newArray) {
list *hashTable[3000];
hashTableCreate(newArray, hashTable);
}
I know this is to do with the way I am using my pointers but I can't figure it out. Any help would be appreciated.
There are several problems on this code:
You seem you are using extra asterisks when assigning newNode to hashTable.
You can use ++ operator to increment count, and use -> to access a member of a pointer to struct.
getWord is unknown to me, but seems impossible it can return a pointer to a string contained inside an element of hashTable, which means the next if will always be false (newNode's word is a copied string, not a pointer to array's word), as it compares memory addresses instead of strings.
You never free temp neither hashTable elements, which seems another misconception of what you are doing here.
As noted by #kaylum , you should initialize hashTable so you avoid comparing against unassigned array elements, neither modifying count on them.
hashTable has to be passed as a pointer to hashTableCreate, or this will work on a copied version of it:
Try this:
void hashTableCreate(char *array, list *(*hashTable[])) {
while(arrayPos < getArrayLength(array)) {
char *temp = getWord(array);
int hashVal = hashingFunc(temp);
if((*hashTable)[hashVal] != NULL &&
strcmp((*hashTable)[hashVal]->word, temp) == 0 ) {
(*hashTable)[hashVal]->count++;
}
else {
list *newNode = malloc(sizeof(list));
strcpy(newNode->word,temp);
newNode->count = 1;
(*hashTable)[hashVal] = newNode;
}
free(temp);
}
}
void timeStructures(char *newArray) {
list *hashTable[3000];
int i;
// Initialize hashTable pointers to NULL
for(i = 0; i < 3000; i++) {
hashTable[i] = NULL;
}
hashTableCreate(newArray, &hashTable);
// Free hashTable elements, malloc'ed at hashTableCreate
for(i = 0; i < 3000; i++) {
if(hashTable[i] != NULL) {
free(hashTable[i]);
}
}
}
Note 1: you never check if hashVal is higher than 3000, which might be fine if you know what you are doing, aka, you know hashingFunc will never return 3000 or higher. If you do not, you'll need to care about growing hashTable appropriately.
Note 2: executing getArrayLength on each loop might be a performance problem for large lists. You probably prefer to create a variable to contain its value and execute it only once.
Note 3: It might be some easier if you declare hashTable as a plain list of elements, not a list of pointers to elements, like list hashTable[3000];, but I don't know exactly what you're looking for. Also, it will always waste 3000 list elements of memory, so might be a performance problem.
I'm passing a file pointer to a function(A) which then opens the file, reads a line in a while loop (for each line in the file) and calls another function(B) using theses values. The issue is after running through function B once, the file pointer becomes NULL and I'm not sure why.
void readMatrixData(matrix *matrix, FILE *fileInput)
{
char buffer[30];
while(fgets(buffer, 30, fileInput) != NULL) {
char *splitString = strtok(buffer, ",");
int row = atoi(splitString);
splitString = strtok(NULL, ",");
int column = atoi(splitString);
splitString = strtok(NULL, ",");
int value = atoi(splitString);
insertNewNode(&matrix->rowArray[row], &matrix->columnArray[column], value, row, column);
}
}
I check if fopen returns NULL before calling function A, and it's not. I've also set a breakpoint on the while loop and the first time it hits, fileInput has some memory allocated. However, on the second loop fileInput becomes NULL and I'm not sure why.
EDIT:
Here's the insertNewNode function:
void insertNewNode(node **rowHead, node **columnHead, int value, int row, int column) {
//Get to the correct position in the column linked list
if (*columnHead == NULL) {
*columnHead = malloc(sizeof(node));
} else {
while((*columnHead)->nextColumn != NULL && (*columnHead)->nextColumn->row < row)
*columnHead = (*columnHead)->nextColumn;
}
//Get to the correct position in the row linked list.
if (*rowHead == NULL) {
*rowHead = malloc(sizeof(node));
} else {
while((*rowHead)->nextRow != NULL && ((*rowHead)->nextRow->column < column))
*rowHead = (*rowHead)->nextRow;
}
node *newNode = malloc(sizeof(node));
newNode->column = column;
newNode->row = row;
newNode->value = value;
(*columnHead)->nextColumn = newNode;
(*rowHead)->nextRow = newNode;
}
The structs involved are:
typedef struct matrix {
node **rowArray;
node **columnArray;
Size matrixDimensions;
} matrix;
typedef struct node {
int value;
int row;
int column;
struct node *nextColumn;
struct node *nextRow;
} node;
and I initialise the matrix arrays with:
node *columns[m->matrixDimensions.columns];
node *rows[m->matrixDimensions.rows];
for (int i=0; i< m->matrixDimensions.columns; i++)
{
columns[i] = NULL;
}
for (int i=0; i < m->matrixDimensions.rows; i++)
{
rows[i] = NULL;
}
m->columnArray = columns;
m->rowArray = rows;
Probably the function insertNewNode overwrites memory
Prefer strtol over atoi.
As #DavideBerra suggested, comment out the call to insertNewNode and step through the code to confirm you can make multiple iterations of your while loop.
I don't understand how you are initialising your matrix arrays using m->matrixDimensions.columns and m->matrixDimensions.rows. Are you using C99 VLAs?
Crank up the warning levels of your compiler and ensure zero-warning compilation.
You do not initialize the nextRow and nextColumn fields of your newly allocated node. Doing so should prevent you from at least some trouble. It is strange that you do not get a Segfault.
You are also mixing array and linked list, what could happen if you get "overflowing" values from your file ? I feel like the segfault is not far away from here. Be very careful, your code shows weird concept mixing !
As others had suggested you, comment your insertNewNode call and see if your loop is well performed. If it is, run your program step by step using a debugger. Hope this helps, good luck !
check the value of row and column before accessing matrix->rowArray and matrix->columnArray whether these values are less than the array size.
My guess is that the values row,column may be outside your matrix and thus overwriting memory. Add a check of the values you receive and make sure your matrix is large enough. Remember arrays are zero indexed in C.
The following program stores every word and then prints them with a number of occurrences.
Global typedef declaration:
typedef struct {
char * word;
int occ;
}
words;
words *data=NULL;
I have a problem with the search function. I've created a function returning int that looks like this: (max is the constantly updated size of an array of structures, that's why I call search function after EOF is reached.)
int search(char *word,int max)
{
int i;
for(i=0; i<max; i++)
{
if(!strcmp(data[i].word,word)) return i;
}
return -1;
}
But I noticed I'm supposed to write a search function having that prototype:
struct abc *find(char *word)
So I've created the following code:
struct words *findword(char *word)
{
struct words *ptr;
for (ptr = data; ptr != NULL; ptr++) { /* IS THE STOP CONDITION OK? */
if (strcmp(word, ptr->word) == 0)
return ptr;
}
return NULL;
}
And I receive many errors during compilation:
reverse.c: In function ‘findword’:
reverse.c:73: warning: assignment from incompatible pointer type
reverse.c:73: error: increment of pointer to unknown structure
reverse.c:73: error: arithmetic on pointer to an incomplete type
reverse.c:74: error: dereferencing pointer to incomplete type
reverse.c: In function ‘main’:
reverse.c:171: error: ‘which’ undeclared (first use in this function)
reverse.c:171: error: (Each undeclared identifier is reported only once
reverse.c:171: error: for each function it appears in.)
make: * [reverse.o] Error 1
which is an int variable assigned to the return of my firstly written search function.
The error with which is easily fixed, but I don't know how to replace that (solution working with my base search function):
data[which].occ++;
How to fix it so that it'll work with my new approach to search?
EDIT
main() added:
int main(int argc, char **argv)
{
char *word;
words *temp;
int c,i,num;
/*int which;*/
FILE *infile;
if(argc!=2) {}
if((infile=fopen(argv[1],"r"))==NULL) {}
num=0;
while(1)
{
c=fgetc(infile);
if(c==EOF) break;
if(!isalpha(c)) continue;
else ungetc(c,infile);
word=getword(infile);
word=convert(word);
/*which=search(word,num);*/
if(findword(word))
{
if(!(temp=realloc(data,sizeof(words)*(num+1))))
{}
else
data=temp;
data[num].word=strdup(word);
data[num].occ=1;
num++;
}
else
data[which].occ++;
free(word);
}
sort(num-1);
for(i=0;i<num;i++)
{}
free(data);
if(fclose(infile))
{}
return 0;
}
I've left {} for the irrelevant pieces of code eg. error handling.
EDIT2
The things I'm asking for above, are fixed. However, I get a seg fault now.
I'll give a link to the whole code, I don't want to put it in an edited post since it'd create a big mess. Seg fault is caused by lines 73 and 152 (strcmp is not working somehow). Hope that full code will be easier to understand.
FULL CODE
The problems are with your findword function, lets go through all the lines
struct words *ptr;
This is not what you ment to do. The typedef you used in defining the structure allows you to not need to write struct anymore. This is why you're getting the error: reverse.c:73: error: increment of pointer to unknown structure. What you want is just:
words *ptr;
Next, the loop:
for(ptr=data; //This is fine, you're assigning your local ptr to the global data. I assume that's something valid
ptr != NULL; //That could OK too... we can loop while ptr is not NULL
ptr++) //This line makes no sense...
You may want to look up how for loops work again, the point is you're incrementing something until it hits a condition. ptr++ will move where you're pointing too, so you'll no longer be pointing to your structure.
I need to see your main() function to understand what you're trying to accomplish, but based on the prototype you have to follow, I think the easiest solution would be something like:
void main()
{
// init your vars
bool more_words_to_add = true;
words *ptr = NULL;
int i;
// populate your array of words
while(more_words_to_add) {
for(i = 0; i<max; i++) {
if(ptr = findword("word")) //if we find the word
ptr->occ++; //increment the number of times we found it
else {
//I don't know what you want to do here, it's not clear what your goal is.
//Add the new word to your array of words and set occ to 1,
//then increment max because there's one more word in your array?
}
}
//get the next word to fine, or else set more_words_to_add = false to break
}
}
If this type of solution is what you're looking to do, then you can adjust your findwords function to be very simple:
struct words *findword(char *word)
{
words *ptr = data;
if (strcmp(word, ptr->word) == 0)
return ptr;
return NULL;
}
EDIT: For your new error I suspect the problem is with your memory allocation, see this short example of using your structure:
words *findword(char *word)
{
words *ptr = data;
if(strcmp(word, ptr->word) == 0)
return ptr;
return NULL;
}
int main(){
words *ptr;
data = realloc(data, sizeof(words));
data->word = "hello"; //DO NOT SKIP THESE LINES
data->occ = 0; //DO NOT SKIP THESE LINES
if(ptr = findword("hello")) {
ptr->occ++;
printf("I found %d %s's\n",ptr->occ, ptr->word);
}
}
mike#linux-4puc:~> ./a.out
I found 1 hello's
You can see here that you need to alloc some memory for the global structure then you can store data in it and pass pointers to it.
EDIT 2:
Your main() code does this:
if((ptr = findword(word)))
{
//do stuff
}
else
ptr->occ++;
That's not going to work because if findword() fails it returns NULL, so in the if check ptr is set to NULL, then in the else you're trying to deference NULL. If (and keep in mind I'm not really reading your logic so this is up to you) you really want to increment ptr->occ if a word is not found then you want this instead:
if(findword(word))
{
ptr = findword(word);
//do stuff
}
else
ptr->occ++; //increments the current ptr's occ, no new ptr was assigned.
for (ptr = data; ptr != NULL; ptr++) {
/* IS THE STOP CONDITION OK? */
No. Your pointer just keeps getting incremented. The only thing that would make it NULL in that code is integer overflow. You could look at what it points to, and see if that is NULL, IF you preset the data area to 0's:
#define NUM_WORDS 100
data = calloc(NUM_WORDS,sizeof(words));
Or
#define NUM_WORDS 100
int bytes = NUM_WORDS * sizeof(words);
data = malloc(bytes);
memset(data,0,bytes);
....
for (ptr = data; ptr->word != NULL; ptr++) {
If you don't want to preset the data area to 0 then you will have to pass the current amount of structs currently held in the data area to your function in order to know how much to loop.
There's no such thing as struct words in your program; there's an unnamed struct type, and a typedef words to that type. Either use struct words or words consistently.
You'll then need to replace
data[which].occ++;
with
result->occ++;
where result is the return value from your new search function.
I have a queue of set length implemented as a dynamic c array implemented like this:
typedef struct {
float* queue;
int size;
int pointer;
} QueueStruct;
void createQueue(QueueStruct* queueInstance, int size){
queueInstance->queue = malloc(sizeof(float)*size);
queueInstance->size = size;
queueInstance->pointer = 0;
}
void addElementToQueue(QueueStruct* queueInstance,float element){
queueInstance->queue[pointer] = element;
if (queueInstance->pointer == queueInstance.size - 1){
queueInstance->pointer = 0;
} else {
++queueInstance->pointer;
}
}
void freeQueue(QueueStruct* queueInstance){
free(queueInstance->queue);
}
And I want to implement this function:
float* returnQueue(QueueStruct queueInstance){
//I want this function to malloc a new float* and then put the queue in it in the
// correct order, from start to finish, as pointed too by the pointer.
//Im not sure how to do this.
}
Any help would be appreciated.
Edit: Corrected a silly programming mistake - this is a simplified version of what is actually in my program.
Let's see if I got that right.
float* returnQueue(QueueStruct *queueInstance){
int j = 0;
float *ret = malloc(sizeof(float)*queueInstance->size); //Allocates the memory you want.
//Copies the elements from pointer to End into the new buffer (assumes, that the array has been filled at least once, add a marker to make sure)
if(queueInstance->FilledOnce) { //Marker variable, explanation as above.
for(int i = queueInstance->pointer; i < queueInstance->size; ++i, ++j)
ret[j] = queueInstance->queue[i];
}
//Copies the newest elements (from beginning to pointer) into the buffer.
for(int i = 0; i < queueInstance->pointer; ++i, ++j)
ret[j] = queueInstance->queue[i];
return ret; //Returns the code in question.
}
To make this code work, you'd have to add 'FilledOnce' to your struct, and amend your 'Add' Code as follows:
void addElementToQueue(QueueStruct* queueInstance, float element){
queueInstance->queue[queueInstance->pointer] = element;
if (queueInstance->pointer == queueInstance.size - 1){
queueInstance->pointer = 0;
queueInstance->FilledOnce = 1;
} else {
++queueInstance->pointer;
}
}
I also advise you, to reset your variables, once you're done with it.
void freeQueue(QueueStruct* queueInstance){
free(queueInstance->queue); //Frees the queue
queueInstance->queue = NULL; //Nulls the reference
queueInstance->FilledOnce = 0;
queueInstance->pointer = 0;
queueInstance->size = 0;
}
This way, if you reuse the struct, you won't run into the problem of trying to access non-allocated memory. Just be sure to check for those variables.
I hope this helps.
I think you should allocate memory for your struct also.
You have made pointer of struct but forgot to allocate memory for that struct
use QueueStruct queuestruct= malloc(sizeof(Queuestruct))
then when you pass this to any of the function above then you can easily allocate
memory for queue poiter in which you can store element for your queue array
This implementation is insufficient. A pointer variable give us location of a tail of queue, but what points to it's head?