I wrote down this code in C to convert a linked list where each node contains a character and convert that list into a string. This is my code
struct node {
unsigned char bit : 1;
struct node *next;
};
//Converts the linked list into a String
char *list_to_bitstring( struct node *head ) {
struct node *countNode = head;
int count = 0;//Counts number of nodes
while ( countNode != NULL ) {
count++;
countNode = countNode->next;
}
char *result = (char *)malloc( sizeof( count + 1 ) );
struct node *temp = head;
int i = 0;
while ( temp != NULL ) {
result[i] = temp->bit;
i++;
temp = temp->next;
}
result[i] = '\0';
return result;
}
//main method
int main() {
struct node *head1 = bitstring_to_list( "111" ); //Converts a String into a linked list
char *result = list_to_bitstring( head1 );
printf( "%s", &result );
return 0;
}
But the output is this-
│
I'm not sure why I'm getting this output. Any advice would be appreciated
From the comments under the question, there are two problems in the code:
The printf is printing the address of the pointer, not the string itself. The printf should be printf("%s\n", result);
The elements of the string need to be converted to the characters '0' and '1'. This can be done by adding '0' to each element of the string, e.g. result[i] = temp->bit + '0';
Related
I'd like to add an element to a list of element. My list is a struct containing a double, an integer and a pointer to the next element. Could someone tell me how to do the Add function please
#include <stdio.h>
#include <stdlib.h>
typedef struct Liste Liste;
struct Liste{
double c;
int n;
Liste* next; // pointe sur l'élément suivant
};
void Add(Liste array, Liste item) {
Liste* last = array.next;
while (last != NULL) {
last = last->next;
}
array.next = &item;
printf("%p\n", array.next);
}
int main(){
Liste array = {12.4, 4, NULL};
printf("%f\n", array.c);
Liste item = {15.4, 7, NULL};
Add(array, item);
printf("%p\n", array.next);
return 0;
}
Pass-by-value
In Add, C makes a copy of all the function parameters; their scope is the function itself. When one returns, the function parameters are popped from the stack and there is no way to get them back, as you have seen. The way to mutate structures is to pass a pointer to the structure, then modify that pointer using the structure pointer dereference operator, (arrow ->.)
Design
The reason one would use a linked-list is it is very cheap to reorder it, but the head of your linked-list is fixed, so you can't change it. You might change this by delineating the container, the list itself, from the contents. This is similar to using a double-pointer, but I think less confusing.
struct Noeud {
double c;
int n;
struct Noeud* next; // pointe sur l'élément suivant
};
struct Liste {
struct Noeud *tete; // singly-linked-list est defini par un pointer seul
};
Then you can add, (I've included assert.h.)
/* `O(n)` */
static void AddQueue(struct Liste *liste, struct Noeud *item) {
assert(liste && item && item->next == NULL);
struct Noeud* last = liste->tete;
if(last == NULL) { // case spécieux
liste->tete = item;
} else {
while (last->next != NULL) {
last = last->next;
}
last->next = item;
}
}
However, it's much simpler and asymptotically faster to add at the beginning of the list.
Pointerstructures like a linked list are powerful tools with a wide rage of application.
But first you have to understand pointers.
A pointer is a datastructure which contains the address of a datastructure.
Whenever you call a function the arguments of it are copied (pushed) to the stack.
If the arguments require a lot of storage space you use a pointer instead.
the code below uses pointers to create a linked list
#include "stdio.h"
#include "stdlib.h"
#include "stdbool.h"
typedef struct List List;
struct List{
double c;
int n;
List *next;
};
void AddItemEnd( List *RootItem, List *Item )
{
List *Last = RootItem;
while( Last->next != NULL )
{
Last = Last->next;
}
Last->next = Item;
}
void AddItemAtPos( List *RootItem, List *Item, unsigned int Pos )
{
if( Pos == 0 )
{
Item->next = RootItem;
}
else
{
List *TempItem = RootItem;
for( unsigned int i = 1; i < Pos && TempItem->next != NULL; ++i )
{
TempItem = TempItem->next;
}
Item->next = TempItem->next;
TempItem->next = Item;
}
}
void RemoveItemAtPos( List *RootItem, unsigned int Pos )
{
if( Pos == 0 )
{
free( (void*) RootItem );
}
else
{
List *TempItem = RootItem;
for( unsigned int i = 1; i < Pos && TempItem->next != NULL; ++i )
{
TempItem = TempItem->next;
}
if( TempItem->next == NULL )
{
return;
}else if( TempItem->next->next != NULL )
{
List *ItemToDelete = TempItem->next;
TempItem->next = TempItem->next->next;
free( (void*) ItemToDelete );
}else
{
free( (void*) TempItem->next );
TempItem->next =NULL;
}
}
}
int main(void) {
List *RootItem = malloc( sizeof( List ));
RootItem->c = 12.4;
RootItem->n = 4;
RootItem->next = NULL;
List *Item1 = malloc( sizeof(List ));
Item1->c = 15.4;
Item1->n = 7;
Item1->next = NULL ;
AddItemEnd( RootItem, Item1 );
List *IterationItem;
printf( "List created with AddItemEnd()\n\n" );
for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem->next )
{
printf( "c: %lf\nn: %d\n\n", IterationItem->c, IterationItem->n );
}
List *item2 = malloc( sizeof( List ));
item2->c = 23.4;
item2->n = 1846;
item2->next = NULL ;
AddItemAtPos( RootItem, item2, 1 );
printf( "\n\nList extended with AddItemAtPos()\n\n");
for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem->next )
{
printf( "c: %lf\nn: %d\n\n", IterationItem->c, IterationItem->n );
}
RemoveItemAtPos(RootItem, 1 );
printf( "\n\nList after RemoveItemAtPos()\n\n");
for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem->next )
{
printf( "c: %lf\nn: %d\n\n", IterationItem->c, IterationItem->n );
}
free( (void*) RootItem );
free( (void*) item2 );
return 0;
}
The key elements when dealing with lists is pointers
and using memory allocation.
If we disregard your add function and just do a simple
example you will probably get the geist of it.
First allocate you starting list like this
Liste* array = malloc(sizeof(Liste));
Now you have one uninitialized block of memory
that array points to. You then need to initialize
it.
array->c = 12.4;
array->n = 4;
array->next = NULL;
in order to add a new entry to your list you
need to again allocate memory for the next node and
initialize it plus set the previous node next pointer
to point to it i.e. array->next.
Liste* item = malloc(sizeof(Liste));
item->c = 15.4;
item->n = 7;
item->next = NULL;
array->next = item;
now you have a list of two elements where array points
to the first
printing your short list
Liste* p = array;
while (p != NULL)
{
printf("%lf %d %p\n", p->c, p->n, p->next);
p = p->next;
}
So your Add functions does not allocate memory and copies
the parameters so that is not going to work.
Your Add function should have a pointer either to either the first or last item in your list e.g.
void Add(Liste* start, double c, int n)
Then you do as I showed you above and create a new node and assign the values
If you want to be able to pass an empty list to Add then you need to do differently, since start is copied it cannot be changed, you need to pass the address of the pointer
void Add(List** start, double c, int n)
{
Liste* node = malloc(sizeof(Liste));
...
(* put node in the list *)
if (*start == NULL)
{
*start = node; // first
}
else
{
(* find last node, see print loop *)
(* once you have last item, set it to point to node)
}
...
}
int main()
{
Liste* start = NULL;
Add(&start, 12.4, 4);
Add(&start, 15.4, 7);
...
I just learned about hash tables today and I tried to make one in C. I get a segmentation fault at line 90. It seems to store the data and retrieve the data fine. It's just when I try to use strcpy to copy the value in the data to a string in the calling function that I get a segmentation fault. I'm not really sure why this is happening since the data is printing out fine.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define size 100
//creates the lsit where the hash table will be stored
float round(int conver){
conver = conver*10.0f;
conver = (conver > (floor(conver)+0.5f)) ? ceil(conver) : floor(conver);
conver = conver/10.0f;
//If you're using C99 or better, rather than ANSI C/C89/C90, the following will also work.
//conver = roundf(conver*10.0f)/10.0f;
return conver;
}
int hash(char input[]){
//decides where a string should be stored
float number = 0;
for(int i = 0; i < strlen(input); i++){
int toAdd = input[i];
printf("to add: %d", toAdd);
number = number + toAdd;
printf("number: %f", number);
}
printf("number again: %f", number);
number /= strlen(input);
number = round(number);
printf("number divided: %f \n", number);
return number;
}
struct Node{
//blueprint for linked list node
struct Node *Next;
char data[];
};
struct Node *hashTable[];
struct Node *createNode(char *data){
//utility function to create a node in the linked list
struct Node *newNode = malloc(sizeof(struct Node));
newNode->Next = NULL;
strcpy(newNode->data, data);
return newNode;
};
void createHashTable(){
//creates the hash table before anything can be inserted
for(int i = 0; i < size; i++){
hashTable[i] = NULL;
}
}
void addToHashTable(char *input){
//adds to the hash table
int hashed = hash(input);
if(hashTable[hashed] == NULL){
hashTable[hashed] = createNode(input);
}
else{
struct Node *newNode = createNode(input);
newNode->Next = hashTable[hashed];
hashTable[hashed] = newNode;
}
}
char *search(char input[], char *writeTo){
//searches the hash table for a value
int hashed = hash(input);
printf("\nhashed: %d", hashed);
printf("\ndata: %s", hashTable[hashed]->data);
if(hashTable[hashed] == NULL){
strcpy(writeTo, "not found");
return;
}
else if(hashTable[hashed]->Next == NULL){
printf("\nit is: %s", hashTable[hashed]->data);
strcpy(writeTo, hashTable[hashed]->data);
return;
}
else{
struct Node *newNode = hashTable[hashed];
while(newNode != NULL){
if(newNode->data == input){
strcpy(writeTo, hashTable[hashed]->data);
return;
}
newNode = newNode->Next;
}
}
}
int main()
{
//main function
createHashTable();
addToHashTable("124");
char *writeTo;
search("124", writeTo);
printf("%s", writeTo);
return 0;
}
There were some bugs in it.
This code should work. I tried to change your code as minimal as possible.
Dont forget that you have to free() pointerstructures.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#define size 100
int _round(float conver){
conver = (conver > (floorf(conver)+0.5f)) ? ceilf(conver) : floorf(conver);
return (int) conver;
}
int hash(char input[]){
float number = 0;
for(int i = 0; i < strlen(input); i++)
{
int toAdd = (int) input[i];
number = number + toAdd;
}
number /= strlen(input);
number = _round(number);
return number;
}
struct Node{
struct Node *Prev;
struct Node *Next;
char *data;
};
struct Node *hashTable[size];
struct Node *createNode(char data[]){
struct Node *newNode = malloc(sizeof(struct Node));
newNode->Prev = NULL;
newNode->Next = NULL;
newNode->data = malloc( sizeof(char) * (strlen(data)));
strcpy(newNode->data, &data[0]);
return newNode;
};
void createHashTable(){
for(int i = 0; i < size; i++){
hashTable[i] = NULL;
}
}
void addToHashTable(char input[]){
int hashed = hash(input);
if(hashTable[hashed] == NULL){
hashTable[hashed] = createNode(input);
}
else{
struct Node *newNode = createNode(input);
newNode->Next = hashTable[hashed];
hashTable[hashed]->Prev = newNode;
hashTable[hashed] = newNode;
}
}
char *search(char input[]){
int hashed = hash(input);
printf("hashed: %d\n", hashed );
if(hashTable[hashed] == NULL){
char *writeTo = malloc( sizeof( char ) * 9);
strcpy(writeTo, "not found");
return writeTo;
}
else if(hashTable[hashed]->Next == NULL){
char *writeTo = malloc( sizeof(char) * (strlen(input)));
strcpy(writeTo, hashTable[hashed]->data);
return writeTo;
}
else{
struct Node *newNode = hashTable[hashed];
char *data = malloc( sizeof( char) * (strlen(input)));
strcpy( data, &input[0] );
data[strlen(input)] = '\0';
while(newNode != NULL){
if(strcmp(newNode->data, data) == 0 ){
char *writeTo = malloc( sizeof(char) * (strlen(input)));
strcpy(writeTo, newNode->data);
return writeTo;
}
newNode = newNode->Next;
}
free( data );
}
char *writeTo = malloc( sizeof( char ) * 9);
strcpy(writeTo, "not found");
return writeTo;
}
void freeHashTable()
{
struct Node * node;
for( int i = 0; i < size; ++i )
{
node = hashTable[i];
if( node != NULL )
{
while( node->Next != NULL )
{
node = node->Next;
}
while( node->Prev != NULL )
{
node = node->Prev;
free( (void*) node->Next->data );
free( (void*) node->Next );
}
free( (void*) node->data );
free( (void*) node );
}
}
}
int main()
{
createHashTable();
addToHashTable("142");
addToHashTable("124");
char *writeTo;
writeTo= search("142");
printf("%s\n", writeTo );
free( (void*) writeTo);
writeTo = search( "124" );
printf("%s\n", writeTo);
free( (void*) writeTo);
freeHashTable();
return 0;
}
First of all, when I run your code I don't get a segfault. Did you remove the use case where the segfault occured? If not, it could be a difference in our environments.
More importantly, your code seems to be riddled in small problems. If you get to fixing those one by one, then the important logical errors will have nowhere to hide.
Here is a (n unordered and incomplete) list of such problems:
In your round function, you are using floor and ceil, but you never include the math library.
In your search function, you are not returning a char*, you are returning nothing. The function header should reflect that.
In your search function, in the final else statement, in the while loop, the condition of the if statement compares two char* values, whereas I assume you mean to compare two strings.
In some of your print statements, you are not printing a new line or any other whitespace, making the results hard to read.
I've spent many days trying to add strings recursively from a prefix expression like: + 1.5 * 13 2.5 inside a binary tree. I'm using the strtok function to separate elements of the string, but then how can I add the elements to the tree?
My code is very similar to the GeeksForGeeks example: https://www.geeksforgeeks.org/building-expression-tree-from-prefix-expression/, but here they only add characters as data on a node.
typedef struct node {
char * data;
struct node *left, *right;
} node;
// Function to recursively build the expression tree
char* add(node** p, char* a)
{
// If its the end of the expression
if (*a == '\0')
return '\0';
while (1) {
char* q = "null";
if (*p == NULL) {
// Create a node with *a as the data and
// both the children set to null
node* nn = (node*)malloc(sizeof(node));
nn->data = *a;
nn->left = NULL;
nn->right = NULL;
*p = nn;
}
else {
// If the character is an operand
if (*a >= '0' && *a <= '9') {
return a;
}
// Build the left sub-tree
q = add(&(*p)->left, a + 1);
// Build the right sub-tree
q = add(&(*p)->right, q + 1);
return q;
}
}
}
int main()
{
node* s = NULL;
char a[] = "3.5 + 4.7";
// (...) tokens
add(&s, str);
return 0;
}
Thank you very much for your help.
In the example of geeksforgeeks they use char data in the struct. But at your side, you use char * data, so you should use strcpy to copy data from strtok to data of struct. In this case, you have to allocate the memory for thedata of each node. If you do not want to allocate, you can change the char * data in struct node to char data[20].
For example:
node* nn = malloc(sizeof(node));
if(!nn) {
//handle the error
}
nn->data = malloc((sizeof(char)*20) // For example max size of data is equal to 20
char * token = strtok(str, delim); // you choose delim as you want to split the string str
While(token!=NULL) {
strcpy(nn->data, token);
token = strtok(NULL, delim);
}
I have the following linked list data structure:
struct _node {
char *text;
stuct _node *next;
}
I want to write a function that converts this linked list into an array of strings with each string being terminated by \n and the whole array terminated by \0.
For example, if the linked list was:
[first]->[second]->NULL
then the array should look like this:
[f][i][r][s][t][\n][s][e][c][o][n][d][\n][\0]
Here is my attempt:
char *convertToArray(struct _node *head){
assert(head != NULL);
int lines = findLines(head);
int i = 0;
struct _node *curr = head;
char *textBufferArray = NULL; // return NULL if lines == 0
textBufferArray = malloc(charCount(head) + lines + 1);
// malloc enough memory for all characters and \n and \0 characters
if (lines > 0){
while (curr->next != NULL){
strlcpy(textBufferArray[i], curr->text, strlen(curr->text)+1);
// I need to add a new line here
curr = curr->next;
i++;
}
}
I need to add \0 before returning
textBufferArray[charCount(head) + lines] = '\0';
return textBufferArray;
}
Considering you have malloced enough memory it is as simple as this
int i=0...
while(cur)
{
int n =strlen(cur->S),k=0;
while(n--)
giant[i++]=cur->S[k++];
giant[i++]='\n';
cur=cur->next;
}
giant[i++]='\0';
I am trying to get a program to run that basically takes an input string and sends it through some code and sorts it using linked lists alphabetically. I have figured out how to make this work using manual (in the actual code) text input, but I cannot get it to work when I am trying to take input from the user.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct llist {
char *value;
struct llist *next;
};
int compare (struct llist *one , struct llist *two)
{
return strcmp(one->value, two->value);
}
void add(struct llist **pp, char *value, int (*cmp)(struct llist *l, struct llist *r)) {
struct llist *new;
new = malloc(sizeof(*new));
new->value = value;
for ( ; *pp != NULL; pp = &(*pp)->next) {
if (cmp(*pp, new) > 0 ) break;
}
new->next = *pp;
*pp = new;
}
void display(struct llist *ptr) {
for (; ptr != NULL; ptr = ptr->next) {
printf("%s\n", ptr->value);
}
}
int main(void) {
struct llist *root = NULL;
char string;
printf("Please enter a string to be sorted alphabetically and displayed with a character count: ");
string = getchar();
while (string != 10){
add(&root,&string, compare);
string = getchar();
}
display(root);
return 0;
}
looking in the main function I'm quite certain it has something to do with getchar and the fact that it reads characters in as ints, but I can't figure out how to fix this, the output is just a bunch of empty lines. but when the while loop is removed and the strings are entered like below in main, it works fine? why is this so?
int main(void) {
struct llist *root = NULL;
char string;
printf("Please enter a string to be sorted alphabetically and displayed with a character count: ");
add(&root,"t", compare);
add(&root,"h", compare);
add(&root,"i", compare);
add(&root,"s", compare);
add(&root,"m", compare);
add(&root,"y", compare);
add(&root,"t", compare);
add(&root,"e", compare);
add(&root,"x", compare);
add(&root,"t", compare);
display(root);
return 0;
}
the output is now
e
h
i
m
s
t
t
t
x
y
which is correct,
Can anyone help me?
When you write "t" in the example, you get the address of an array. That address is different for each value you pass to add. However, the address of string does not change, and you are setting new->value to the same thing each time you call add. Instead of new->value = value, try new->value = *value (and all of the associated changes necessary).
There are not too many changes needed. Note that terminating after a single string of input is not very nice behavior. A good exercise would be to write a destructor that tears down the string after the first line and then sorts the next. Another nice exercise would be to sort arguments if any are passed, reading stdin if no arguments are given.
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct llist {
char value; /* CHANGE */
struct llist *next;
};
typedef int (*compar)( struct llist *one , struct llist *two );
int
compare( struct llist *one , struct llist *two )
{
return tolower( one->value ) > tolower( two->value ); /* CHANGE */
}
void *
xmalloc( size_t s )
{
void *v = malloc( s );
if( v == NULL ) {
perror( "malloc" );
exit( EXIT_FAILURE );
}
return v;
}
void
add( struct llist **pp, char value, compar cmp ) /* CHANGE */
{
struct llist *new;
new = xmalloc( sizeof *new ); /* Check for errors */
new->value = value; /* CHANGE the type of value above */
for( ; *pp != NULL; pp = &(*pp)->next ) {
if( cmp( *pp, new ) > 0 )
break;
}
new->next = *pp;
*pp = new;
}
void
display( struct llist *ptr )
{
for( ; ptr != NULL; ptr = ptr->next ) {
putchar( ptr->value ); /* CHANGE */
}
putchar( '\n' );
}
int
main( void )
{
struct llist *root = NULL;
char string;
while( (string = getchar()) != '\n' ) { /* Optional CHANGE (1) */
add( &root,string, compare );
}
display(root);
return 0;
}
/*
* (1) Using "'\n'" instead of 10 is necessary for readability,
* portability, and sanity of future maintainers.
*
* Writing getchar() only once is cleaner.
*/
With your hard coded entry code you are passing in string's to add while in your user input code you are only passing in a pointer to a single character. A char* is not necessarily a string in C, it may point to a string, but it doesn't have to.
In C a string is a buffer of characters that ends with a null zero, the character '\0' (which is usually just the value 0). When you are using getchar your are passing a pointer to a character - and that character does not have a null zero after it, so it is not a valid C string.
If you want to keep your code using getchar you need to use a buffer that will store a null zero after that character. You can do that will a small array as below:
int main(void) {
struct llist *root = NULL;
char string[2];
string[1] = '\0'; // Ensure that we have a null terminated string
printf("Please enter a string to be sorted alphabetically and displayed with a character count: ");
string[0] = getchar();
while (string != '\n'){
add(&root,string, compare);
string[0] = getchar();
}
display(root);
return 0;
}
Cleaned-up a few things
1) As #shf301 siad, need to pass a string, not just a pointer to a single char.
2) Need to create copies of the string - notice strdup.
3) While loop should break on '\n and EO and maybe '\0. getchar() returns an int for a reason: EOF and 0 to UCHAR_MAX (e. g. 255).
4) Should free() resources at the end - not shown.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// In case you library does not have strdup() ...
char *strdup(const char *s) {
if (s == NULL) return NULL;
size_t siz = strlen(s) + 1;
char *y = malloc(siz);
if (y != NULL) {
memcpy(y, s, siz);
}
return y;
}
struct llist {
char *value;
struct llist *next;
};
int compare(struct llist *one, struct llist *two) {
return strcmp(one->value, two->value);
}
void add(struct llist **pp, char *value,
int(*cmp)(struct llist *l, struct llist *r)) {
struct llist *new;
new = malloc(sizeof(*new));
new->value = strdup(value);
for (; *pp != NULL; pp = &(*pp)->next) {
if (cmp(*pp, new) > 0)
break;
}
new->next = *pp;
*pp = new;
}
void display(const struct llist *ptr) {
for (; ptr != NULL; ptr = ptr->next) {
printf("%s\n", ptr->value);
}
}
int main(void) {
struct llist *root = NULL;
char string[2];
string[1] = '\0';
printf("Please enter a string to be sorted alphabetically"
" and displayed with a character count: ");
int ch;
while ((ch = getchar()) != EOF && ch != '\n' && ch != '\0') {
string[0] = ch;
add(&root, string, compare);
}
display(root);
return 0;
}