I have been working on a project in C and I am having trouble when trying to copy char* using strcpy/memcpy/strncpy, none of these seem to work. The problem that is arising is that the words that are around 8 or more characters long are not being copied completely.
typedef struct wordFrequency {
char * word;
int frequency;
struct wordFrequency *left, *right;
} *node;
node setnode(char * word) {
node newNode = (node)malloc(sizeof(node));
newNode->word = (char*)malloc(sizeof(word));
strcpy(newNode->word, word); //This is where I'm having trouble
newNode->frequency = 1;
newNode->right = NULL;
return newNode;
}
The code above is what I believe is the main cause for error, but I don't know where to fix it. I have tried messing with the sizes, but that didn't work.
If possible can someone explain to me a way to copy all characters or if I did not allocate enough space?
This program is an mcve that shows how to properly allocate and initialize each node in your linked list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_SIZE(array) \
(sizeof(array) / sizeof(array[0]))
typedef struct wordFrequency {
char *word;
int frequency;
struct wordFrequency *left, *right;
} node;
node *setnode(char *word) {
node *newNode = malloc(sizeof(node));
newNode->word = malloc(strlen(word) + 1);
strcpy(newNode->word, word);
newNode->frequency = 1;
newNode->right = NULL;
return newNode;
}
int main() {
char *wordList[] = {"one", "two", "three"};
node nodeHead;
node *nodePrev = &nodeHead;
node *nodeNext;
for (int index = 0; index < ARRAY_SIZE(wordList); index++) {
nodeNext = setnode(wordList[index]);
nodePrev->right = nodeNext;
nodeNext->left = nodePrev;
nodePrev = nodeNext;
}
for (node *nodePtr = nodeHead.right; nodePtr != NULL; nodePtr = nodePtr->right) {
printf("word = %s, frequency = %d\n", nodePtr->word, nodePtr->frequency);
}
return 0;
}
Output
word = one, frequency = 1
word = two, frequency = 1
word = three, frequency = 1
Note
This program has no error checking and does not free the allocated memory. This code should not be used in a production environment.
Replies to Questions in Comments
I replaced *node with node in the typedef because that allows me to declare instances of node. The other syntax only allows pointers to node.
I use an instance of node instead of node * for nodeHead because any attempt to change its address will be an error.
I use nodePrev to traverse the list and also to provide a target for left in the returned nodes. I initialize nodePrev to &nodeHead because it is the start of the list. I set nodePrev to nodeNext because that's how I chose to traverse the list during initialization. I could have used
nodePrev = nodePrev->right;
and achieved the same effect.
I only implemented list handling so that I could create a self-contained example that would run without changes. You can safely ignore it.
If you want to see good linked list code, I recommend the linux kernel implementation.
Related
I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!
I tried to create a program to add elements to a linked list. The elements consist of name and age. But it fails to add without giving me any error. Could you please show me my mistake?
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX 9999
struct data {
char name[MAX];
int age;
struct data *next;
};
void pushHead(struct data **head, struct data **tail, char name[], int age) {
struct data *node = (struct data *)malloc(sizeof(struct data));
strcpy(node->name, name);
node->age = age;
if (*head == NULL) {
node = *head;
node = *tail;
node->next = NULL;
} else {
node->next = *head;
*head = node;
}
}
void view(struct data *head) {
struct data *curr = head;
if (curr == NULL)
printf("No Data\n");
else {
while (curr != NULL) {
printf("%s(%d)\n", curr->name, curr->age);
curr = curr->next;
}
}
}
int main(int argc, char const *argv[]) {
struct data *head = NULL;
struct data *tail = NULL;
pushHead(&head, &tail, "Felix", 19);
view(head);
return 0;
}
Output : No Output
My code is working when I put the head on global scope (by changing all the functions to work globally), but when I try to put the head in main scope it doesn't work.
In pushHead(), you are doing:
node = *head;
node = *tail;
this end up assigning NULL to node pointer because *head and *tail both are NULL. Note that this is a memory leak as your program loose the memory reference which the node pointer is holding. Instead, you should do
*head = node;
*tail = node;
Some suggestions:
For storing name in the list node, you are taking buffer of size
9999 (MAX macro) which is (IMO) very large. I believe, a buffer
of size 256 is more than enough for this purpose. Or, you can also
have buffer of exact size required for storing name by allocating
the memory dynamically to it. For this , you have to take a char *
member instead of char array for name and allocate memory to it
dynamically based on size of name parameter of pushHead() and in
this case, you need to make sure to free it explicitly when deleting
the list nodes.
When using strcpy() to copy string, make sure that destination
buffer is large enough to contain the source string to avoid
overflows.
Follow good programming practice. Always check malloc return and
ensure to free the allocated memory once you are done with it.
Do not cast the malloc return.
To include standard library header files use <>, i.e. #include "stdio.h" -> #include <stdio.h>, check this.
I have two files (.txt) with phones numbers (one number per line). The files are pretty huge (282 MB), and I am writing a program to check these two files (raw data and DO NO CALL List), and filter out those numbers that does not exist in the DO NO CALL List. Something similar to grep -f raw.txt donotcall.txt -v > filtered.txt
I have implemented a very simple form of hashtable (separate addressing, using linked lists). My code currently, reads the phone numbers from the DoNotCall.txt and stores it in the hashtable. This is the function that I use to generate the hash. THE TABLE SIZE IS 100
int hashgen(char s[])
{
int hash;
hash = (s[0] + s[1] + s[2] + s[3]) * 100 / 13;
return hash;
}
The hashtable: the way I did.
#define TABLESIZE 100
struct node {
char str[30];
struct node *next;
}
struct node *hashtble[TABLESIZE];
struct node *hashtable_alloc(void) //allocates space for a node in the memory
{
struct node *tmp = calloc(1, sizeof(struct node));
strcpy(tmp->str, "~"); //just a string to mark the head of the linked list
tmp->next = NULL;
return tmp;
}
void hashinit(void)
{
struct node *t = NULL;
int i=0;
for(i=0; i<TABLE_SIZE; i++)
ht[i] = hashtable_alloc();
}
void hashtable_add(char s[])
{
struct node *t = NULL;
int arrnum = hashgen(s);
t = calloc(1, sizeof(struct node));
strcpy(t->str, s);
t->next = ht[arrnum];
ht[arrnum] = t;
}
Undoubtedly, I am a naive programmer dealing with hashtables. Please suggest me a better hash function. Though, I have read articles on hashtables, it would be great if anyone can tell me about a better approach, something better than hashtables, or do the hashtable method in a better way. Thanks in advance
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I'm having a small issue here with my linked list.
I built a linked list with strings and it worked perfectly.
Now since i'm using strtok() to separate the string I need help on storing the struct separately but keeping them connected.
Hope i explained it well
for now here's what i've got:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dict_word *word;
typedef struct node *Node;
typedef struct double_linked_list *DLL;
struct dict_word
{
char words[100];
int year[10];
char eng_synonyms[100];
char heb_synonyms[100];
};
struct node
{
word data;
Node *next;
Node *previous;
};
struct double_linked_list
{
Node *head;
Node *last;
};
char *split(char words[100])
{
int i;
char *word=strtok(words, "_#_");
char *year=strtok(NULL, "_#_");; // assigning NULL for previousely where it left off
char *definition=strtok(NULL,"_#_");
char *synonyms=strtok(NULL,"_#_");
i=atoi(year);
printf("%s\n", word);
printf("%i\n",i);
printf("%s\n", definition);
printf("%s\n", synonyms);
return 0;
}
and this is my function to insert node by having only one string:
void insert_beginning(char words[99])
{
struct node *var, *temp;
var=(struct node *)malloc(sizeof(struct node)); //explination about the (node *)
strncpy(var->data, words,99);
if (head==NULL)
{
head=var;
head->previous=NULL;
head->next=NULL;
last=head;
}
else
{
temp=var;
temp->previous=NULL;
temp->next=head;
head->previous=temp;
head=temp;
}
}
I am a bit surprised to see plain C code used to handle such abstract data in 2014.
Nevertheless, I think you should separate the actual book data from the list.
strtok will modify your initial string (inserting '\0' at the end of each token). If you want to access the various bits strtok has split the string into, you must memorize all the pointers to the tokens (word, definition, etc).
So you should create a structure to hold all this together :
typedef struct {
const char * words;
int year;
const char * definition;
const char * synonyms;
} dict_word;
Now to create a new record, you will have to make a copy of the various tokens, just like you did previously in your linked list insertion.
But this time the copy will occur sooner, using the strdup function.
dict_word * create_record (char * raw) // raw record string
{
// allocate a new object
dict_word record = (dict_word *) malloc (sizeof (record));
assert (record != NULL);
/*
* sanity checks left out for concision,
* but you should make sure your input is properly formatted
*/
// populate the fields
record->word = strdup (strtok(raw , "_#_"));
record->year = atoi (strtok(NULL, "_#_"));
record->definition = strdup (strtok(NULL, "_#_"));
record->synomyms = strdup (strtok(NULL, "_#_"));
// done
return record;
}
You will need a cleanup function to free all the memory allocated during record creation:
void delete_record (record * r)
{
// first free all strings
free (r->word);
free (r->definition);
free (r->synomyms);
// then free the object
free (r);
}
Now for the list.
Instead of mixing up the code that handles the list with the one that cares about books, you can define the list as a more independent object:
typedef struct sNode {
struct sNode * next;
struct sNode * prev;
void * data; // this will point to the linked objects
} listNode;
typedef struct
{
listNode *head;
listNode *tail; // either first/last or head/tail, but keep it consistent :)
} List;
First you will need to initialize the list:
void List_init (List * l)
{
l->head = l->tail = NULL;
}
Then you will want to add elements to it
void List_put (List * list, void * data)
{
// allocate a node
listNode * node = (listNode *) malloc (sizeof (node));
assert (node != NULL);
// store data reference
node->data = data;
// insert the node at the end of list
node->prev = list->tail;
node->next = NULL;
list->tail = node;
if (list->head == NULL) list->head = node;
}
Finally, to use all this:
// create the list
List book_list;
List_init (&book_list);
/* ... */
// create the records
char * raw_record;
while ((raw_record = read_from_database ()) != DONE_READING)
{
List_put (book_list, create_record (raw_record));
}
/* ... */
// browse the records
listNode * node;
for (node = book_list->head; node != NULL; node = node->next)
{
dict_word * record = (dict_node *) node->data;
// do whatever you want with your record
}
All this being said and done, C is inadequate at best to handle this kind of high-level data.
You could write a very much more compact, reliable and efficient equivalent in a variety of more modern languages, starting with C++.
Now if you're just a student asked by an old geezer of a professor to do some dusty C homework and hoping to get it done for you by an old geezer of a StackOverflow contributor, well... it's your lucky day.
I've been trying to add a new node into a linked list of profiles (for ex. facebook profiles), and I'm getting a runtime error while launching. This is what I got :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
typedef struct friend {
char *name;
int age;
char gender;
struct friend* next;
} friend;
void node_add(friend* new);
int main(int argc, char *argv[]) {
friend amit;
friend *new;
amit.name = "amit";
amit.age = 16;
amit.gender = 'm';
node_add(new);
new->name = "amit";
printf ("name: %s\n", new->name);
system("PAUSE");
return 0;
}
void node_add(friend* new) {
new = (friend* )malloc(sizeof(friend));
friend* head = new;
new -> next = head;
}
I'm trying now to create a delete node function. I tried to find which node does the user wants to delete, and then delete it by doing
delete -> next = delete -> next -> next
The problem is, I need to get for the first node in the list.
Here is what I wrote:
void node_delete(friend* delete) {
friend *temp;
char name[256];
int i = 0, j = 0;
printf ("Please enter the friend's name you want to delete: \n");
fgets (name, 256, stdin);
fgets (name, 256, stdin);
while (0 == (strcmp(temp -> next -> name, delete -> next -> name))) {
temp = friend -> next;
}
temp -> next = temp -> next -> next;
free (delete);
}
Edit:
It seems my test was a mite too quick, because there is in fact a pretty serious problem with this code, but it's subtle:
In main() you are never actually pointing new at anything. It's just a garbled pointer out into memory space, which might sometimes work, and most of the time, is just terrible.
friend *new; // here's your problem; change this to:
friend *new = malloc(sizeof(friend));
Also, never cast the results of malloc.
Reedit:
How a very simple linked list implementation might look:
typedef struct _node node;
struct _node {
void *payload;
node *next;
};
node *create_node () {
node *retval = malloc(sizeof(node));
retval->payload = NULL;
retval->next = NULL;
return retval;
}
node *add_node (node *target) {
if (target->next)
return;
node *next = create_node();
node->next = next;
}
node *node_search (node *haystack, void *needle) {
while (haystack) {
if (!compare(needle, haystack->payload)) {
return haystack;
} else {
haystack = haystack->next;
}
}
return NULL;
}
Implementation of deletion and insertion are left as an exercise to the reader.
Of course, you alloc memory and assign it to local variable.
If you want to change pointer, pass pointer with one more asterix.
And, by the way, do not name anything like friend or new. Its keywords in C++,
and it create not needed problems.
You should have friend *head global.
And in the
void node_add(friend* new)
{
new = (friend* )malloc(sizeof(friend));
new->next = head;
head = new;
}
You should use a double-pointer.
void node_add(friend **new) {
*new = malloc(sizeof(friend));
/* etc */
}
The issue is in the following line:
amit.name = "amit";
You should be a malloc and doing a strcpy()