I have a linked list whose elements are of type
typedef struct List * News;
struct List
{
char * Text;
News NextN;
};
In the main function I declared an array of type News as follows
News PTH[50];
for (i = 0; i < 50; i++)
{
PTH[i] = (News) malloc(sizeof(struct List));
PTH[i] -> Text = NULL;
PTH[i] -> NextN = NULL;
}
I added new nodes in the beginning of the list with
if ( PTH[i] -> Text == NULL)
PTH[i] -> Text = msg;
else
{
t -> Text = msg;
t -> NextN = PTH[i];
PTH[i] = t;
}
Where msg is a array of char of length 2000; and and then tried to print the texts apointed by PTH[i] -> Text with
p = PTH[i];
if (p -> Text != NULL)
{
printf("%s", p -> Text);
p = p -> NextN;
}
while (p != NULL)
{
printf("%s", p -> Text);
p = p -> NextN;
}
}
This algorithm only add one node. The error is how I define the PTH or is there an error in how I put nodes in the list.
maybe it is something like this you are after:
if ( PTH[i]->Text == NULL )
{
PTH[i]->Text = msg;
}
else // first create node, then append by first finding the last node
{
News it = NULL;
News t = malloc( sizeof(struct List));
t->Text = msg;
t->NextN = NULL;
for ( it = PTH[i]->NextN; it != NULL; it = it->NextN)
{
;
}
it->NextN = t;
}
Assuming that msg is a buffer you use to receive new data, you have to be careful with this statement:
PTH[i] -> Text = msg;
Since msg is a pointer to char, the assignment will not copy the characters sequence; instead, it will just make PTH[i]->Text point to the same location as msg. This is problematic if you change the contents in msg - the changes are, of course, reflected back in every PTH[i]->Text for which the assignment was made, namely, every node that you ever added. Probably, not quite what you want. This is why it seems like you can only handle one node at a time. They all get the same text, because they all point to the same memory location.
You should use strcpy instead:
strcpy(PTH[i]->Text, msg);
Don't forget to include string.h.
This assumes that PTH[i]->Text is already allocated. You might want to use strncpy if there is a chance that msg exceeds 2000 characters, to avoid buffer overflows.
If you didn't alloc space for PTH[i]->Text, you could allocate exactly strlen(msg)+1 positions for PTH[i]->Text and then use strcpy safely. Or you could use strdup, also declared in string.h, which has exactly this behavior:
PTH[i]->Text = strdup(msg);
Related
I'm trying to create an alphabetically ordered linked list from a file by placing the node in the correct spot after reading it. The file must not be alphabetically ordered. The program reads the file correctly and I'm able to add everything at the end of the list.
Place search_place(Place first, char *new){
Place aux = first;
while (aux->abcnext != NULL){
if ( strcmp(new,aux->place) > 0)
aux = aux->abcnext;
else
break;
}
return aux;
}
void insert_place(Place first, char* string){
Place previous,temp,new;
previous = search_place(first, string);
if (previous->abcnext == NULL){
new = create_place();
previous->place = string;
new->abcnext = previous->abcnext;
previous->abcnext = new;
}
else{
new = (Place)malloc(sizeof(place_node));
new->place = string;
new->abcnext = previous;
previous = new;
}
}
Place create_place(){
Place aux;
aux=(Place)malloc(sizeof(place_node));
if (aux!=NULL){
aux->place=malloc(25*sizeof(char));
aux->abcnext=NULL;
}
return aux;
}
typedef struct placenode*Place;
typedef struct placenode{
char *place;
Place abcnext;
}place_node;
Considering the results that I've obtained from this code I suppose the problem is related to either pointers or the header of the linked list or both. With 4 places: P, Z, W, L - I get only P -> Z from the list.
if (previous->abcnext == NULL){
new = create_place();
previous->place = string;
new->abcnext = previous->abcnext;
previous->abcnext = new;
}
A couple of obvious problems with the above code. Firstly, you don't set new->place - you replace previous->place which doesn't seem right. So your new node will have NULL for it's "place" and you'll have lost the value for the previous node.
Secondly you're assigning the value of string rather than making a new copy. If you're using the same string each time you call the function, you'd end up with all the nodes pointing to the same string.
You should do something like
new->place = malloc(strlen(string)+1);
strcpy(new->place, string);
or if your version of C has it, use strdup
new->place = strdup(string);
(to preface this my C is terrible)
I'm trying to send a string from iOS to a BLE device. I encode the string in swift and write it like this:
func sendUserName(userName: String) {
let bytes: [UInt8] = Array(userName.utf8)
print(bytes.count)
let data = NSData(bytes: bytes, length: bytes.count)
capsenseLedBoard!.writeValue(data, forCharacteristic: userIdCharacteristic, type: CBCharacteristicWriteType.WithResponse)
}
I send in this string "THISISATEST123456789" and this line print(bytes.count) prints out 20.
I recieve the data on the BLE device like this and pass it to the below userDidConnect function:
userDidConnect((char *)wrReqParam->handleValPair.value.val);
I have a struct called Event that looks like this:
struct Event {
char time[20]; // The time in ISO 1601 format
char name[3]; // The two character name of the event. See header for declarations.
char userId[20]; // The userId of the connected user if one is present.
struct Event* next;
};
I have a global variable declared like this:
char currentlyConnectedUserID[20];
I then have an enqueue function that looks like this:
/**
Creates a new Event and adds to the linked list.
#param time The time in ISO 8601 format.
#param name The name descriptor of the event ("VS", "VO", etc.)
#param userId The id of the user who is currently connect (if they are connected).
*/
void enqueueEvent(char time[20], char name[3], char userId[20]) {
struct Event* temp = (struct Event*)malloc(sizeof(struct Event));
strncpy( temp->time, time, 20);
strncpy( temp->name, name, 3);
strncpy( temp->userId, userId, 20);
temp->next = NULL;
if(front == NULL && rear == NULL) {
front = rear = temp;
return;
}
rear->next = temp;
rear = temp;
}
I have a function that accepts a new userId and then creates a new Event off of it and adds it to the linked list..well this is what it's suppose to do:
void userDidConnect(char *userId)
{
size_t destination_size = sizeof(userId);
snprintf(currentlyConnectedUserID, destination_size, "%s", userId);
//enqueueEvent("2007-03-01T13:00:20", "UC", currentlyConnectedUserID);
showMessageInUART(currentlyConnectedUserID, sizeof(currentlyConnectedUserID));
}
Currently if I run the userDidConnect method above I'm able to printout the currentlyConnectedUserID properly. However, if I uncomment out this line:
//enqueueEvent("2007-03-01T13:00:20", "UC", currentlyConnectedUserID);
I get a "crash". I'm doing this in a fairly obscure IDE (PSoC Creator from Cypress) so I don't see any error logs or IDE crash logs. The only way I can tell is that the showMessageInUART is never called, so I know it has to be that line.
I'm able to successfully create and enqueue a new Event if I do this:
enqueueEvent("2007-03-01T13:00:20", "UC", "1234567891234567891");
My only thought is that maybe the size of the array is wrong? Maybe? Or perhaps there is some trailing \0 that is screwing things up?
Suggestion updates:
I've tried doing this:
size_t destination_size = strlen(userId) + 1;
Which gives the correct value into currentlyConnectedUserID however enqueueing still causes a crash.
--
I've replaced strcpy with strncpy which is still causing a crash ;(
--
Tried this to ensure I didn't overflow which still didn't work:
sprintf(currentlyConnectedUserID, "%.19s", userId);
UPDATE
I updated my enqueue to look like this since don't have breakpoints:
void enqueueEvent(char time[20], char name[3], char userId[20]) {
UART_UartPutString("start enqueue");
struct Event* temp = (struct Event*)malloc(sizeof(struct Event));
UART_UartPutString("1");
strncpy( temp->time, time, 20);
UART_UartPutString("2");
strncpy( temp->name, name, 3);
UART_UartPutString("3");
strncpy( temp->userId, userId, 20);
UART_UartPutString("4");
temp->next = NULL;
UART_UartPutString("5");
if(front == NULL && rear == NULL) {
front = rear = temp;
return;
}
rear->next = temp;
rear = temp;
}
This line is crashing:
strncpy( temp->time, time, 20);
aka we never make it here: UART_UartPutString("2");
If I call this same function from main it works fine. Any idea why it would be crashing here when called from a different method?
The strcpy funtion Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
Therefore, I propose you to change the enqueueEvent funtion, using strncpy instead of dangerous strcpy as :
void enqueueEvent(char time[20], char name[3], char userId[20]) {
struct Event* temp = (struct Event*)malloc(sizeof(struct Event));
strncpy( temp->time, time,20);
strncpy( temp->name, name,3);
strncpy( temp->userId, userId,20);
temp->next = NULL;
if(front == NULL && rear == NULL) {
front = rear = temp;
return;
}
rear->next = temp;
rear = temp;
}
Change also the allocation of temp pointer from local stack of the enqueueEvent function to global level because the pointer allocation is vanished when going outside of the function.
I don't know why I can read the Linked list without problems in LABEL : 1 ; but the program just crashes and print grabage in the LABEL : 0 ;
In other terms, why the linked list works fine inside the lecture function , but not outside it ?
Here is my code :
/* including libraries */
#define V 20
typedef struct DATA{
char* NomP;char* NomA;
struct DATA *Next;
}DATA;
// Prototypes .
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = MALLOC(sizeof (DATA)); int len = lecture_data(fs,HEAD);
print_data(HEAD,len); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA *ROOT)
{
char cNom[V],cArticle[V];
int eofs=0;int i=0;
while(!eofs)
{
DATA *Data = MALLOC(sizeof (DATA));
fscanf(fs,"%s %s",cNom,cArticle);
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if( i==0 )
{
Data -> Next = NULL ;
ROOT = Data ;
}
else
{
DATA* Ptr = ROOT ;
while( (Ptr->Next) != NULL )
{
Ptr = (Ptr -> Next);
}
Data -> Next = NULL ;
Ptr -> Next = Data ;
}
i++;
eofs = feof(fs) ;
// check ferror(fs) here
}
puts("Start of reading :");
print_data(ROOT,len); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
Here is the printing function :
void print_data(DATA *L_ROOT,int len)
{
int i = 0 ;
DATA* LINK;
LINK = L_ROOT;
while( LINK != NULL )
{
printf("%d : DATA->NomA : %s\n",i,LINK->NomA);
printf("%d : DATA->NomP : %s\n",i,LINK->NomP);
LINK = LINK -> Next ;
i++;
}
}
You're allocating data for the root of the list in the main function, and pass that to the function so that it may populate the list, but the first time you allocate an element you overwrite the ROOT pointer value.
this makes you lose the only connection between the function and the outside world (since the return value is just a number), so the HEAD value in main() is left pointing at nothing meaningful (because your function never uses it), while the list remains allocated in some memory location that no one outside is pointing to, which means it's lost. Running valgrind would have been able to identify this.
You can fix that by changing the (i==0) case from -
ROOT = Data ;
into
ROOT->next = Data ;
but make sure you're ignoring the data of the root node later on.
p.s. - using capitalized variables and types is not considered a good idea (it's mostly reserved for macros). It also makes your code look like you're shouting :)
The (main) problem is that lecture_data doesn't use it's input parameter (ROOT) for storage of the linked list, nor does it return the internal generated list. The correct way to handle this is to have ROOT reference the calling scope's parameter so that it can update it's reference as necessary.
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = NULL;
int len = lecture_data(fs, &HEAD);
print_data(HEAD); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA **ROOT)
{
char cNom[V],cArticle[V];
int i=0;
DATA *current = *ROOT; // grab the passed in reference
while(!feof(fs))
{
if(fscanf(fs,"%s %s",cNom,cArticle) <= 0) // This call is only successful if the return value is > 0
{
// check ferror(fs) here
continue; // Can also "break;" here, essentially, it's eof already
}
DATA *Data = MALLOC(sizeof (DATA));
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if(NULL == current) // ROOT was uninitialized before the call
{
Data -> Next = NULL;
*ROOT = Data;
}
else
{ // We don't need to iterate the list in every step.
Data->Next = current->Next; // This part allows the function to insert nodes in the middle / end of an existing list
current->Next = Data;
current = Data;
}
i++;
}
puts("Start of reading :");
print_data(ROOT); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
Note: print_data didn't do anything with the len parameter, so no need passing it in at all.
This solution is not wasteful in terms of "empty" nodes in the list (as opposed to having an empty head to ignore), and is suitable both for initializing the list from scratch AND for cases where you need to append / insert into an existing list.
I'm trying to create a linked list structure to store data. The head of the linked list seems to be updating somehow. I have the following code. I can't seem to figure out how put char array data into a node and keep it from updating when the address to said char array's data updates.
The following code prints out whatever string is passed into the processStr function. How do I keep head from updating ?
//Linked List Structure
mainNode *head = NULL;
//take and store word in data structure
void processStr(char *str){
//char array
char strArray[sizeof(str)+1];
//stores lower case string
char strLower[strlen(str)];
int i;
for(i = 0; str[i]; i++)
strLower[i] = tolower(str[i]);
strLower[i] = '\0';
//printf("%s : ", strLower);
//Starts Linked List
if(head == NULL){
mainNode *mainPtr = (mainNode *)malloc(sizeof(mainNode));
nameNode *namePtr = (nameNode *)malloc(sizeof(nameNode));
mainPtr->name = strLower;
mainPtr->numOccurances = 1;
mainPtr->next = NULL;
mainPtr->nextName = namePtr;
namePtr->name = strArray;
namePtr->next = NULL;
head = mainPtr;
}
printf("%s : " , head->name);
}
You assign the pointers mainPtr->name and namePtr->name to variables strLower and strArray that are declared locally in processStr(). That means after that function returns, any access to these pointers results in undefined behaviour. You could do sth. like
mainPtr->name = strdup( strLower );
instead to allocate memory for the strings.
Btw.: strLower must also be declared as char strLower[strlen(str)+1];
The above code will only run once only which will add information to head only once. If you want to add more information in case of second run then add code for else condition. Example:-
if ( head == NULL ) {
// code to insert data in case of first run
}else{
// code to insert data for second run and so.....
}
I am currently using a list in structs that looks like this:
This is a function in which removes elements from a list. I start with a for loop to go through the entire list. If i is less than the number of entries it enters an if statement. Then it the old position into a hold ptr. Makes the old on = to NULL and then moves the list so that the elements below take its spot.
Heres a sample list when I call this function:
100
125
150
When I do this and I want to remove 150 from the list it goes through but looses access to memory in the list -> wlist_ptr[i] -> eth_address. I then get a set fault. Is there any way around loosing track?
There's a big mistake in the loop.
Only one element is "moved up", and it's moved up after it's set to null.
So, this
list -> wlist_ptr[i] = NULL;
list->wlist_ptr[i-1] = list->wlist_ptr[i];
Needs to change to this to prevent moving the NULL up:
list->wlist_ptr[i-1] = list->wlist_ptr[i];
list -> wlist_ptr[i] = NULL;
But then, a loop is needed to iterate through the remainder of the list to move them up as well. memmove is your friend for this. Keep in mind too, that when that's done, you don't want to increase i for the next iteration, because the next element in the list will now be at the original i location.
Perhaps this will do the job:
struct wifi_info_t *wifilist_remove(struct wifilist_t * list, int user_address)
{
int i;
int count;
struct wifi_info_t *ptr;
ptr = NULL;
count = wifilist_number_entries(list);
// TODO: take out the ( ptr == NULL ) logic if more than one match needs to be
// removed.
for(i=0; ( i < count ) && ( ptr == NULL ); i++)
{
if(list -> wlist_ptr[i] -> eth_address == user_address)
{
ptr = list -> wlist_ptr[i];
if ( i < ( count - 1 ) )
memmove(&(wlist_ptr[i]), &(wlist_ptr[i + 1]), (count - (i + 1)) * sizeof(wlist_ptr[0]));
// TODO: decrement the length of the list returned by
// wifilist_number_entries(list)
}
}
if(ptr != NULL)
{
list->wlist_entries--;
}
return ptr;
}
Note that I just typed this here, so it may have syntax errors or the like.
Some example:
struct wifi_info_t *wifilist_remove(struct wifilist_t * list, int user_address)
{
int i;
struct wifi_info_t *ptr;
ptr = NULL;
for(i=0; i < wifilist_number_entries(list); i++)
{
if(list -> wlist_ptr[i] -> eth_address == user_address)
{
ptr = list -> wlist_ptr[i];
if(i != (wifilist_number_entries(list) -1))
{
//replace it with last element
list -> wlist_ptr[i] = list -> wlist_ptr[wifilist_number_entries(list)-1];
list -> wlist_ptr[wifilist_number_entries(list)-1] = ptr;
}
//you can use free and realloc there if you want
list->wlist_entries--;
}
}
//why? don't do that
return ptr;
}