C function call with struct array - c

So I'm trying to do some practice in C by trying to create a dynamic array of structs, but I'm running into some difficulty when trying to pass the struct into different functions for different operations.
My code so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
char *str;
int len;
};
//& gives address of value, * gives value at address
int main(void) {
struct node **strarray = NULL;
int count = 0, i = 0;
printf("hello\n");
strarray = (struct node **)realloc(strarray, (count + 1) * sizeof(struct node *));
/* allocate memory for one `struct node` */
strarray[count] = (struct node *)malloc(sizeof(struct node));
strarray = init(strarray);
return 0;
}
struct node ** init(struct node ** strarray){ //this is the line that's causing problems
int i = 0, count = 0;
char line[1024];
if(fgets(line, 1024, stdin) != NULL) {
/* add ONE element to the array */
strarray = (struct node **)realloc(strarray, (count + 1) * sizeof(struct node *));
/* allocate memory for one `struct node` */
strarray[count] = (struct node *)malloc(sizeof(struct node));
/* copy the data into the new element (structure) */
strarray[count]->str = strdup(line);
strarray[count]->len = strlen(line);
count++;
return **strarray;
}
}
void printarray(){
for(i = 0; i < count; i++) {
printf("--\n");
printf("[%d]->str: %s", i, strarray[i]->str);
printf("[%d]->len: %d\n", i, strarray[i]->len);
}
}
I haven't worked on the printarray method yet, I'm trying to get the function declaration and the pass to work. Currently, I'm getting a conflicting types for ‘init’
struct node** init(struct node** strarray)
error which I have tried many fixes to, but no avail.

You're problem is that you're derefenrecing the variable you're returning.
Do
return strarray
Instead of
return **strarray
Here is the whole function:
struct node ** init(struct node ** strarray){
int i = 0, count = 0;
char line[1024];
if(fgets(line, 1024, stdin) != NULL) {
/* add ONE element to the array */
strarray = (struct node **)realloc(strarray, (count + 1) * sizeof(struct node *));
/* allocate memory for one `struct node` */
strarray[count] = (struct node *)malloc(sizeof(struct node));
/* copy the data into the new element (structure) */
strarray[count]->str = strdup(line);
strarray[count]->len = strlen(line);
count++;
return strarray;
}
}

Related

C: Avoid garbage values in linked-list

Suppose a word has multiple meanings in the dictionary. Actually, In my dictionary, one node has 5 meanings. So when I lookup the word, the program prints 2 meanings along with other 3 garbage values 100 characters long.
How can I avoid them from being printed?
Here's my code:
struct node{
char word[20];
char meaning[5][100];
struct node *next;
};
void lookup(struct node *head, char *word)
{
int found = 0, i;
while(head != NULL)
{
if(strcmp(head->word, word) == 0)
{
found = 1;
printf("\n\t%s", word);
for(i = 0; i < 5; i++) printf("\n\t%s", head->meaning[i]);
printf("\n");
break;
}
head = head->next;
}
if(found == 0) printf("\nWord not found in the dictionary!!");
}
Allocate your node elements with calloc or do memset after malloc, so that all the memory (or members) of your node are filled with 0's by default.
struct node *node_element = (struct node *) calloc(1, sizeof(struct node));
Then print the meanings by checking length,
for(i = 0; i < 5; i++) {
if(strlen(head->meaning[i]) > 0)
printf("\n\t%s", head->meaning[i]);
}

C adding struct which has been initialized by a function overrides original

Node.h
typedef struct Node Node;
struct Node{
int rank;
int marked;
size_t nSize;
size_t nCapacity;
char * name;
Node * predecessor;
Table * weights;
void (*print)(Node * toPrint); ///< print function for printing all info
Node ** neighbors;
};
void init_node(Node ** node, char * name, void (*printNode)(Node * n));
Node.c
void init_node(Node ** node, char * name, void (*printNode)(Node * n)){
*node = (Node *) malloc(sizeof(Node));
if ( node == NULL ){
assert(NULL);
}
(*node)->rank=0;
(*node)->marked=0;
(*node)->nSize=0;
(*node)->name=name;
(*node)->predecessor=(Node *)malloc(sizeof(Node));
if ( (*node)->predecessor == NULL ){
assert(NULL);
}
(*node)->nCapacity = INITIAL_CAPACITY;
(*node)->neighbors=(Node **)calloc((*node)->nCapacity, sizeof(Node *));
if ( (*node)->neighbors == NULL ){
assert(NULL);
}
(*node)->weights = create(strHash, strEquals, strLongPrint );
(*node)->print = printNode;
}
main.c
for (size_t i = 0; i < TEST_AMOUNT ; i++){
char str[TEST_AMOUNT + 1] ="";
sprintf(str, "%zu", i);
Node * n = malloc(sizeof(*n));
init_node(&n, str, printNode);
nodes[i] = *n;
nodes[i].print(&nodes[i]);
}
printf("First: %p Second: %p\n", (void *)&nodes[0].name, (void *)&nodes[1].name);
printf("\n\nCreated an array of %d Nodes\n\n", TEST_AMOUNT);
for (size_t i = 0; i < TEST_AMOUNT; i++){
nodes[0].print(&nodes[0]);
}
So I have this node class, and I keep having this issue when I create a node then initialize it in a for loop like above then assign that value to the array. The array then contains TEST_AMOUNT number of the same node rather then a series of nodes labeled 0-TEST_AMOUNT.
I don't seem to have this problem when I create a node and initialize it outside of the for loop, and was curious as to what was causing this.
You don't need to call malloc() before calling init_node. init_node() allocates the space for the node, and assigns to the caller's variable -- that's why you have to pass the address of the variable.
You don't show the declaration of the nodes array, but it should be declared as an array of pointers. Then you'll need to indirect through these pointers to access the data in the nodes.
Node *nodes[TEST_AMOUNT];
for (size_t i = 0; i < TEST_AMOUNT ; i++){
char str[TEST_AMOUNT + 1] ="";
sprintf(str, "%zu", i);
init_node(&nodes[i], str, printNode);
nodes[i]->print(nodes[i]);
}

How to store values with same memory location in c?

If I have a file stream with content
123 1234
1223 124235
21432 325
In my program I read line by line of the file and store the first target of each line into my list. These line with same location and when I run the program it will keep pointing to the most recent data and place it in to list. Which means If I have a function called printL() in while loop. It will print
123/
1223/1223/
21432/21432/21432/
instead of
123/
123/1223/
123/1223/21432
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct n{
char *value;
struct n *next;
} Node;
void printList(Node *head){
Node *cur = head;
while(cur!=NULL){
printf("%s/", cur->value);
cur = cur->next;
}
printf("\n");
}
void insertIntoList(Node **head, char *data){
Node *newNode = malloc(sizeof(Node));
if (newNode == NULL){
perror("Failed to allocate a new node for the linked list");
exit(1);
}
newNode->value = data;
newNode->next = NULL;
Node *currentList = *head;
if(*head == NULL){ //if the linked list head is null, then add the target into linked list
*head = newNode;
}
else{
while(currentList->next!=NULL){
currentList = currentList->next;
}
currentList->next = newNode;
}
}
int main(int argc, char**argv){
FILE *fileStream;
size_t len = 0;
char *line = NULL;
Node *head = NULL;
int j;
for(j=1; j<argc-2;j++){
fileStream = fopen(argv[j], "r");
if(fileStream == NULL){
fprintf(stderr, "could not open");
continue;
}
insertIntoList(&head,"a"); /////////////Line 95
insertIntoList(&head,"b");
insertIntoList(&head,"c");
insertIntoList(&head,"d");
printf("here is a try\n");
printList(head);
while(getline(&line, &len, fileStream)!=EOF){ /////////////Line 101
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
printf("######print head here is##########\n");
printList(head);
printf("######print head here is##########->\n");
}
//printList(head);
}
return 0;
}
In order to keep the content of each loaded field returned from strtok(), just add a strdup() before calling insertIntoList() after checking if not a null-pointer.
In your code, if you compare the value of both line and targetNum
are the same. If fact, the strtok() function returns a pointer to
the input string and keep the pointer for the next argument.
Replace the following code:
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
By that one:
char *targetNum = strtok(line, " \t\r\n");
if (targetNum != NULL) {
printf("*****%s\n", targetNum);
insertIntoList(&head, strdup(targetNum));
}
You don't store the contents of the string in your list nodes; you store a pointer to the buffer used for the contents of the string.
Consider changing your list node structure to
typedef struct node Node;
struct node {
Node *next;
char data[];
};
where the contents of the string are stored in the C99 flexible array member.
Your node constructor is then something like
Node *new_node(const char *data)
{
const size_t datalen = (data) ? strlen(data) : 0;
Node *result;
result = malloc(sizeof (Node) + datalen + 1);
if (!result) {
fprintf(stderr, "Out of memory!\n");
exit(EXIT_FAILURE);
}
if (datalen > 0)
memcpy(result->data, data, datalen);
result->next = NULL;
result->data[datalen] = '\0';
return result;
}
See how the function allocates memory for the copy of the data?
Personally, I prefer something like
typedef struct node Node;
struct node {
Node *next;
size_t hash;
size_t size;
char data[];
};
where the size member is basically strlen(data) (except that you can also use the nodes to hold binary data that includes nul bytes \0), and hash is a simple hash computed from data. hash is useful if you intend to compare the entire contents of nodes; if two nodes' lengths or hashes differ, then it is certain their contents differ; if they are the same, then you compare them character by character (memcmp(node1->data, node2->data, node1->length) == 0 if they are the same).
The constructor for the above is something like (using DJB2 hash):
Node *new_node(Node *next, const void *data, const size_t size)
{
Node *result;
result = malloc(sizeof (Node) + size + 1);
if (!result) {
fprintf(stderr, "new_node(): Out of memory (%zu bytes)\n", size);
exit(EXIT_FAILURE);
}
/* Copy and hash data using DJB2 hash (not that good, but fast) */
{
unsigned char *src = (unsigned char *)data;
unsigned char *const end = (unsigned char *)data + size;
unsigned char *dst = result->data;
size_t hash = 5381;
while (src < end) {
hash = hash * 33 + (size_t)(*src);
*(dst++) = *(src++);
}
/* Add terminator */
*dst = '\0';
}
result->next = next;
result->hash = hash;
result->size = size;
return result;
}
These Nodes can also be used in e.g. hash tables, which makes the type quite versatile.

Linux device driver read write functions issue

I'm writing sample device driver to read and write using cyclic buffer, it means the last node point to the first one. I created the linked list of 10 block, each block buffer size = 5.
now on my write function, when I call write method, it write in the buffer, check if it's filled, then jump to the other one, the next write will write in the current buffer + offset defined in lnod struct . same thing for read.
when I run the echo command twice
echo 123456789 > /dev/driver
echo abcd > /dev/driver
according to the write and read function below the cat command will give123456789abcd as result since the second write will continue on the offset, so the read function will read all the size_to_read, but the cat (called 3 times)command gave me this :
cat /dev/driver
abcd
6789
abcd
some usefull code parts:
static int BlockNumber = 10;
static int BlockSize = 5;
static int size_to_read = 0;
data buffer structure
typedef struct dnode
{
int bufSize;
char *buffer;
struct dnode *next;
} data_node;
liste stucture
typedef struct lnode
{
data_node *head;
data_node *cur_write_node;
data_node *cur_read_node;
int cur_read_offset;
int cur_write_offset;
}liste;
static liste newListe;
the create liste method is called in init function
write function
static ssize_t sample_write_liste(struct file *f, const char *buf, size_t size, loff_t *offset)
{
if (*(offset) == 0)
{
size_to_read += size;
}
int size_to_copy;
size_to_copy = MIN (size, BlockSize - newListe.cur_write_offset);
copy_from_user(newListe.cur_write_node->buffer + newListe.cur_write_offset, buf, size_to_copy);
*(offset) += size_to_copy;
newListe.cur_write_offset += size_to_copy;
if (newListe.cur_write_offset == BlockSize)
{
newListe.cur_write_node = newListe.cur_write_node->next;
newListe.cur_write_offset = 0; // we erase previous things
}
return size_to_copy;
}
the read function
static ssize_t sample_read_liste(struct file *f, char *buf, size_t size, loff_t *offset)
{
int size_to_copy;
size_to_copy = MIN (size_to_read - *(offset), BlockSize - newListe.cur_read_offset);
copy_to_user(buf, newListe.cur_read_node->buffer + newListe.cur_read_offset,size_to_copy);
newListe.cur_read_offset += size_to_copy;
(*offset)+=size_to_copy;
if (newListe.cur_read_offset == BlockSize)
{
newListe.cur_read_node = newListe.cur_read_node->next;
newListe.cur_read_offset = 0;
}
return size_to_copy;
}
create linked list function
static void createlist (void) {
data_node *newNode, *previousNode, *headNode;
int i;
/* new node creation */
newNode = (data_node *)kmalloc(sizeof (data_node), GFP_KERNEL);
newNode->buffer = (char *)kmalloc(BlockSize*sizeof(char), GFP_KERNEL);
newNode->next = NULL;
newListe.head = newNode;
headNode = newNode;
previousNode = newNode;
for (i = 1; i < BlockNumber; i++)
{
newNode = (data_node *)kmalloc(sizeof (data_node), GFP_KERNEL);
newNode->buffer = (char *)kmalloc(BlockSize*sizeof(char), GFP_KERNEL);
newNode->next = NULL;
previousNode->next = newNode;
}
/* cyclic liste : we should tie the last element to the first one (head) */
newNode->next = headNode;
newListe.cur_read_node = headNode;
newListe.cur_write_node = headNode;
newListe.cur_read_offset = 0;
newListe.cur_write_offset = 0;
}
In the createlist() routine , in the for loop, you need to add the follwoing line to make a circular list.
previousNode = newNode;
Your existing createlist would create a circular list with just two nodes.
for (i = 1; i < BlockNumber; i++)
{
newNode = (data_node *)kmalloc(sizeof (data_node), GFP_KERNEL);
newNode->buffer = (char *)kmalloc(BlockSize*sizeof(char), GFP_KERNEL);
newNode->next = NULL;
previousNode->next = newNode;
previousNode = newNode //Please add this line to make the list circular.
}

Description is only printing out for the last one entered

I'm quite new to C and I'm trying to implement a binary tree in C which will store a number and a string and then print them off e.g.
1 : Bread
2 : WashingUpLiquid
etc.
The code I have so far is:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 300
struct node {
int data;
char * definition;
struct node *left;
struct node *right;
};
struct node *node_insert(struct node *p, int value, char * word);
void print_preorder(struct node *p);
int main(void) {
int i = 0;
int d = 0;
char def[LENGTH];
struct node *root = NULL;
for(i = 0; i < 2; i++)
{
printf("Please enter a number: \n");
scanf("%d", &d);
printf("Please enter a definition for this word:\n");
scanf("%s", def);
root = node_insert(root, d, def);
printf("%s\n", def);
}
printf("preorder : ");
print_preorder(root);
printf("\n");
return 0;
}
struct node *node_insert(struct node *p, int value, char * word) {
struct node *tmp_one = NULL;
struct node *tmp_two = NULL;
if(p == NULL) {
p = (struct node *)malloc(sizeof(struct node));
p->data = value;
p->definition = word;
p->left = p->right = NULL;
}
else {
tmp_one = p;
while(tmp_one != NULL) {
tmp_two = tmp_one;
if(tmp_one->data > value)
tmp_one = tmp_one->left;
else
tmp_one = tmp_one->right;
}
if(tmp_two->data > value) {
tmp_two->left = (struct node *)malloc(sizeof(struct node));
tmp_two = tmp_two->left;
tmp_two->data = value;
tmp_two->definition = word;
tmp_two->left = tmp_two->right = NULL;
}
else {
tmp_two->right = (struct node *)malloc(sizeof(struct node));
tmp_two = tmp_two->right;
tmp_two->data = value;
tmp_two->definition = word;
tmp_two->left = tmp_two->right = NULL;
}
}
return(p);
}
void print_preorder(struct node *p) {
if(p != NULL) {
printf("%d : %s\n", p->data, p->definition);
print_preorder(p->left);
print_preorder(p->right);
}
}
At the moment it seems to work for the ints but the description part only prints out for the last one entered. I assume it has something to do with pointers on the char array but I had no luck getting it to work. Any ideas or advice?
You're always doing a scanf into def and then passing that to your insert routine which just saves the pointer to def. So, since all of your entries point to the def buffer, they all point to whatever was the last string you stored in that buffer.
You need to copy your string and place a pointer to the copy into the binary tree node.
The problem is that you're using the same buffer for the string. Notice your struct is holding a pointer to a char, and you are passing the same char array as that pointer each time.
When you call scanf on the buffer, you are changing the data it points to, not the pointer itself.
To fix this, before assigning it over to a struct, you can use strdup. So the lines of code would become
tmp_*->definition = strdup(word);
Keep in mind that the char array returned by strdup must be freed once you are done with it, otherwise you'll have a leak.

Resources