I'm doing a Forth interpreter in C. I can't decide how to better implement the Forth dictionary.
struct Word {
struct Word* next;
char* name;
int* opcode;
// int arg_count;
}
struct Dictionary {
struct Word words;
int size;
}
opcode is a sequence of codes - functions of word. So each opcode[i] corresponds to some function. I suppose it should be some table with elements [opcode<->function pointer]. But how to implement it?
We don't know the size of function. We can't use void* (or we can?) since we must somehow having only opcode execute the function.
What should I do?
Some variation on this definition is quite common in traditional Forth implementations:
typedef int cell;
typedef void code_t (struct Word *);
struct Word
{
char name[NAME_LENGTH];
struct Word *next;
code_t *code;
cell body[]; /* Upon instantiation, this could be zero or more items. */
};
The dictionary will then be a list linked through the next pointer. The words are allocated sequentially, interleaving the struct Word header, and the body data.
To execute a word, call word->code(word);. The function pointed to by code can then decide what to do with body. The body could be data, or it could be what you call "opcodes".
A colon defintion will have code pointing at something like this:
void docolon (struct Word *word)
{
/* IP is a variable holding the instruction pointer. */
rpush (IP); /* Push the current instruction pointer to the return stack. */
IP = (struct Word *)word->body; /* Start executing the word body (opcodes). */
}
Whereas a primitive word, e.g. + would look like
void plus (struct Word *word)
{
cell n1 = pop();
cell n2 = pop();
push (n1 + n2);
}
All of this below is based on an assumption: You want to declare function pointers.
typedef int (*OPCODE)(char *);
struct Word
{
struct Word* next;
char* name;
OPCODE *opcode;
// int arg_count;
};
opcode is a function pointer to a function that returns an integer and takes a char * as the argument. A really good page of short tutorials on function pointers is The Function Pointer Tutorials by Lars Engelfried.
Related
I'm making a program in C. Basically I have a struct that contains some fields, and an array of pointers. Each struct has an pointer array that points to another struct forming a "connection" between them. I'm trying to get the value of a field that is stored at the memory address the pointer that is pointing at it.
Suppose this. I have two of these nodes in memory. A and B. A has a pointer inside A's array that is a reference to B. To get this pointer I'd have to do something like this:
*temp_ptr = (*ptr).pointer_array[0]
This would get the pointer address *ptr and give it to *temp_ptr.
Now what I am wondering is this. How can i do this? When I try this, I get "Expression must have struct or union type"
When I try this in lets say Java I could do this
int variable = field[0].fieldIWantToGet
I'd get the desired outcome.
Heres an image to clarify the intended behaviour that I'm trying to get. Link to behavior
Where Struct A is in a "global" collection of structs and has a array of pointers that lead to other Structs, such as B
Here is some code from my project.
#define GLOBAL_PTR_ARRAY_SIZE 10
Node* global_node_array[10];
typedef struct Node{
unsigned char node_id;
int *ptr_array[10];
int ptr_array_size;
}Node;
void append_connection(short position, short destination) {
Node* position_ptr = global_node_array[position];
Node* destination_ptr = global_node_array[destination];
if ((*position_ptr).ptr_array_size < GLOBAL_PTR_ARRAY_SIZE) {
int current_ptr_array_size = (*position_ptr).ptr_array_size;
(*position_ptr).ptr_array[current_ptr_array_size] = destination_ptr;
(*position_ptr).ptr_array_size++;
}
void print_id(Node* ptr) {
node* dptr = NULL;
dptr = ptr->ptr_array[0];
pptr = (int) (*ptr).ptr_array[0];
fprintf(stdout, "%d connection to %d exists", (*ptr).node_id, dptr-
>node_id);
}
int main(int argc, char const *argv[])
{
append_connection(0,1);
print_id(global_node_array[0]);
return 0;
}
Your picture shows array of the structs not the pointers. But the example below covers both.
struct a{
int field1,field2;
}
struct b{
struct a m[10];
}
struct c{
struct a *m[10]
}
/* and usage */
struct c *x;
struct b *y;
x -> m[5].field1;
y -> m[5] -> fileld1;
I have a stack that contains two types of struct. Struct Stud and Struct Prof.
When I want to push something I created two Push functions for both structs. Although I would like it to be with one function but its ok I can bear with it.
Now to Pop. If I want to Pop a student from the Stack, do I have to make a Pop function specifically for Students only? The same with Professors?
How can I store the item if I don't know what type is it? What type must the element be, to store the item there?
Here are the structs:
struct MyStack
{
int head;
void **stack;
int size;
};
typedef struct MyStack STACK;
struct stud
{
char flag;
char fname[50];
int semester;
};
struct prof
{
char flag;
char fname[50];
char course[30];
};
Now to create the Pop function. What do type of item do I pass in the function?
int Pop(STACK *stack,int *head,??? *elem)
{
if(stack->head<=-1)
return 0;
*elem=stack->stack[*head];
*head--;
return 1;
}
You have to encode the type information when you push, simplest is probably to type tag:
#define STUD 0
#define PROF 1
struct stack_entry {
int type;
void *item;
};
struct MyStack
{
int head;
struct stack_entry *stack;
int size;
};
Then change your push functions to attach the right tag when you push. Then, in pop, simplest again is probably to just return a stack_entry struct, and let the calling function figure it out. At that point you might want a snazzier name than "stack_entry" though. Also, it would be slightly preferable to use a union:
struct stack_entry {
int type;
union {
struct stud *stud;
struct prof *prof;
} item;
}
Because then the compiler can help you out a bit, but of course you still have to be more or less as careful as you would be with a void *.
Edit: initialization...
You don't have to mark then end of the buffer with anything, since you have a size variable in the struct. But if you wanted to do that I would have that be its own type
#define END_OF_BUFFER 1
#define STUD 2
#define PROF 3
And then for init you could do:
stack->size = size;
stack->stack = calloc(sizeof(*stack->stack), size + 1);
stack->stack[size].type = END_OF_BUFFER;
stack->head=-1;
Though I tend to use "head" to refer to a pointer that points to the next place to write to, but I'm not sure how standard that is. But the buffer is an array of strack_entries, not void *'s.
I have this:
typedef struct nodebase{
char name[254];
char sex;
int clientnum;
int cellphone;
struct nodebase *next;
struct nodebase *encoding;
} clientdata;
I have added clientdata *curr[]; in seperate function. The reason why I made *curr into *curr[] instead is that this client data will be stored in a .txt file. So I came up with singly linked-list to read all the data and when the program fscanf every 5th variable, I will add 1 to clientcounter.
So, the *curr[] will be *curr[clientcounter].
Now, I need to convert this pointer array into char array named temp[clientcounter] because char array is needed to evaluate something else later in the code.
I came up with this code below:(Using Tiny C on Windows)
void loaded_data_transfer(clientdata *curr,clientdata temp[],int clientcounter)
{
clientdata temp[] = {0};
temp[clientcounter].name = curr[clientcounter]->name;
temp[clientcounter].sex = curr[clientcounter]->sex;
temp[clientcounter].clientnum = curr[clientcounter]->clientnum;
temp[clientcounter].cellphone = curr[clientcounter]->cellphone;
}
The problem is, Tiny C is giving me an error: lvalue expected at temp[clientcounter.name = ... part. Can anyone tell me what did I do wrong?
And if anyone knows a better way to keep track of the curr of clientdata by using counter and by using singly linked-list, please let me know.
You cannot assign an array to another. You should use strcpy or strncpy
strcpy(temp[clientcounter].name, curr[clientcounter]->name);
Maybe you meant to copy the entire struct:
void loaded_data_transfer(clientdata * curr, clientdata temp[], int clientcounter)
{
temp[clientcounter] = *curr; // Copy entire struct
}
It should work, because your struct doesn't any pointer members.
I am assuming you use it like this
clientdata * curr[CURR_SIZE];
clientdata temp[TEMP_SIZE];
/* init curr elements here */
loaded_data_transfer(*curr[clientcounter], temp, clientcounter);
Also, your declaration should be:
void loaded_data_transfer(clientdata *curr[],...
C structure question
I have a list of words and their corresponding frequencies:
word 10
the 50
and 35
overflow 90
How should I hold this data in a structure? Should I use a two dimensional array? I should also note I have to sort them by their frequency, so I'm thinking an array of some sort then apply qsort, but I need to preserve the integers so if I use a char array I have to do back and forth casting
Possibly a struct:
struct WordInfo {
char *word;
int frequency;
};
Then you can make an array of these structs:
struct WordInfo words[128]; // whatever
And finally write a comparator function like this:
int word_compare(const void *p1, const void *p2)
{
struct WordInfo *s1 = p1;
struct WordInfo *s2 = p2;
return s1->frequency - s2->frequency;
}
If you know the maximum number of characters for the string which you are going to handle means use array and int data type inside a structure.
typded struct _data
{
char word[MAX_CHARS];
int freq;
}DATA;
...
DATA *d = malloc(sizeof(DATA) * n);
If you dont know the max characters of word go for pointer charater char *word;. In this case memory allocation will happen for each entry which will affect the performance and it will cause more fragmentation.
Its better to allocate a chunk of memory once rather than allocating small memory for n times.
You can also have an array of std::pair
Then you can run whatever sorting algorithm you want to sort the array based on the second element.
For example you will have:
std::pair myArray[size];
Define a structure type, something like
struct wordAndFrequency
{
char *word;
int count;
};
then take an array of struct wordAndFrequency and qsort that.
typedef struct Dict {
char *word;
int frequency;
} Dictionary;
Now create array of this structure object and use it as hashmap. When you come across a word, see if this word is there, increment the counter else add this word with count as 1.
Dictionary *dictionary=(Dictionary*)malloc(sizeof(Dictionary)*SIZE);
I have the following structure:
struct hashItem {
char userid[8];
char name[30];
struct hashItem *next;
};
In the function below I take a char pointer (char array) argument that I wish to assign to the struct.
void insertItem(struct hashItem *htable[], char *userid, char *name)
{
int hcode = hashCode(userid);
struct hashItem *current = htable[hcode];
struct hashItem *newItem = (struct hashItem*) malloc(sizeof(struct hashItem));
newItem->userid = userid;
newItem->name = name;
[...]
}
Instead I get the following error:
hashtable.c: In function ‘insertItem’:
hashtable.c:62: error: incompatible types in assignment
hashtable.c:63: error: incompatible types in assignment
Line 62 and 63 are the `newItem->..." lines.
You almost certainly don't want to just assign the char* to the char[] - as the compiler points out, the types are incompatible, and the semantics are not what you think. I assume you want the struct members to contain the values of the two char* strings - in which case, you want to call strncpy.
strncpy(target, source, max_chars);
You should chang your struct in
struct hashItem {
char userid[8];
char *name;
struct hashItem *next;
};
to assign a char pointer to a name. In the struct you defined
char name[30] are just 30 chars.
You can't assign a pointer to a string to a character array like you are trying to. Instead you need to copy the contents of the string with strncpy as Adam indicated:
strncpy (newItem->userid, userid, 8);
When you declare the struct with a character array in it, you are allocating memory inside the structure itself to store a string of the given length.
When you pass a pointer into your function, you are passing a memory address (an integer) that indicates where a null-terminated string can be found.
To assign the pointer to the array doesn't make sense. The array has memory allocated for it already -- it can't be made to "point" to another location.
While you can use pointers in your structure, you need to be very careful that when you assign them, you are telling them to point to something that is going to be valid for the duration of the time you will use the structure. For example, this code is bad, because the string passed to insertItem no longer exists after fillStructure returns:
struct hashItem
{
char * userid;
};
void insertItem (struct hashItem * item, char * userid)
{
item->userid = userid;
}
void fillStructure (struct hashItem * item)
{
const char string[] = "testing";
insertItem (item, string);
}
int main(void)
{
struct hashItem item;
fillStructure (&item);
/* item->userid is now a dangling pointer! */
}
For more, I would recommend reading the "Arrays and Pointers" chapter of the C FAQ -- start with Question 6.2 and keep reading from there.