I am using the linked list example from junghans and try to make it work
with some server code. In the char array, I could insert a host (from inet_ntoa)
and update it's age. So I can send one packet to the daemon, but then it crashes.
I tried setting next_pointer=start_pointer; because from what I read, it will be
a circular list. However, after receiving the second packet, strcpy crashes..
Questions:
How do I point to the beginning, if next_pointer=start_pointer doesn't do the trick?
Do I need to free, before overwrite a member of the char array?
struct x {
char name[20];
int age;
struct x *next_rec;
};
struct x *start_pointer;
struct x *next_pointer; // starting hosts, will be overwritten
char *names[] = {
"127.0.0.1",
"evil666",
"192.168.56.101",
""
};
int ages[] = {0,20,30,0};
// some other code
while (1) {
sleep(1);
us=time(NULL);
printf("%ld, Sleep a second\n", us);
buf[0] = 0x0;
current_host = 0x0;
memset (buf,0,sizeof buf);
if(recvfrom(s, buf, BUFLEN, 0, (struct sockaddr*)&si_other, &slen)==-1)
diep("recvfrom()");
current_host = inet_ntoa(si_other.sin_addr);
if(!current_host)
diep("inet_ntoa()");
/* linked list initialization */
/* Initalise 'start_pointer' by reserving
* memory and pointing to it
*/
start_pointer=(struct x *) malloc (sizeof (struct x));
if(!start_pointer)
diep("start pointer on holiday");
/* Initalise 'next_pointer' to point
* to the same location.
*/
next_pointer=start_pointer;
/* Put some data into the reserved
* memory.
*/
strcpy(next_pointer->name,current_host);
next_pointer->age = ages[count];
/* Loop until all data has been read */
while ( ages[++count] != 0 )
{
/* Reserve more memory and point to it */
next_pointer->next_rec=(struct x *) malloc (sizeof (struct x));
if(!next_pointer)
diep("next pointer on holiday");
strcpy(next_pointer->name, names[count]);
next_pointer->age = ages[count];
}
next_pointer->next_rec=NULL;
next_pointer=start_pointer;
/* insert new record, update age */
while (next_pointer != NULL)
{
printf("%s ", next_pointer->name);
if(strstr(next_pointer->name,current_host)) {
printf("%d \n", next_pointer->age+1);
}
if(!strstr(next_pointer->name,current_host)) {
printf("%d \n", next_pointer->age);
}
next_pointer=next_pointer->next_rec;
}
next_pointer=start_pointer; // XXX
The problem with your code is that you missed this part from the linked C file in the init loop: next_pointer=next_pointer->next_rec. As a result, in first iteration you allocate new list node, but then modify contents of the first node. And then in subsequent iterations you allocate even more nodes, but you still only modify the first node.
Then right after the loop you terminate the list, but since you did not update next_pointer in the meantime, you're list has now a single node. (And you leaked some memory there, overwriting addresses with next allocations and NULL, so now you cannot free it.)
As to your more specific questions:
Question 1: next_pointer is only a helper variable to iterate over a list. If you want a circular list, you should set some next_rec pointer to start_pointer. You could do it like this:
for (next_pointer = start_pointer;
next_pointer->next_rec != NULL; /* This is not the last node. */
next_pointer = next_pointer->next_rec /* Move to the next node. */)
;
/* At this moment next_pointer points to the last node of the list. */
next_pointer->next_rec = start_pointer; /* And a cycle is there. */
However, you can actually do this while initialising your loop. When you exit from the init loop, next_pointer is indeed pointing at the last node. So instead of doing next_pointer->next_rec=NULL to terminate the list, do next_pointer->next_rec = start_pointer to make a cycle.
UPDATE That is, if you do want a circular list. Because in fact next_pointer=start_pointer will make next_pointer point at the beginning. So I assumed you want the end of the list point to the beginning (as you mentioned circular list).
Question 2: If you didn't allocate a string, explicitly (with malloc) or implicitly (for example with strdup), you don't need to free it. In particular in that code there are no strings to free:
next_pointer->name is an array within structure. You allocated it along with the structure (list node), and it will be freed with the node.
names is an array of pointers to the constant strings. They were not allocated, but instead will be part of data section of application compiled code, and thus cannot be freed.
Last but not least: lookout for strcpy. If you are copying only IPs there, 20 characters will always be enough, but the first moment you'll try to copy something larger, you have buffer overflow and can overwrite some other data. You should be using strncpy, with n = 19, followed by next_pointer->name[19] = 0 to ensure null termination.
And you don't need to run strstr() twice there. It either returns NULL pointer or not, so you could run
if (strstr( /* .. the arguments .. */ )) {
/* ... */
} else {
/* what if the call did return NULL. */
}
Related
I followed a quite straight forward pseudo code for implementing a linked list of a struct in c, here it is:
pseudo code for struct linked list
The problem i am facing is memory loss after adding the 4th node:
After the 4th addition, the 4th node points to the 3rd node, which points to a weird address.
prior to the 4th addition, the 3rd node pointed to the 2nd node - how did i lose the memory?
here's my code:
RailPart *headPart = NULL;
void createRailPart(char *partInfo, char *connectTypes){
char sPart[1];
char ePart[1];
char len[MAX_FIELD_SIZE];
char price[MAX_FIELD_SIZE];
char *noneDigit;
//allocate memory
RailPart *toPush = (RailPart*)malloc(sizeof(headPart));
if (toPush == NULL){
return;
}
//initialize data
sscanf(partInfo, "%[^,],%[^,],%[^,],%[^,]", sPart, ePart, len, price);
(*toPush).start = sPart[0];
(*toPush).end = ePart[0];
for (int i = 0; i < (int) strlen(connectTypes); i++){
if ((toPush)->end == connectTypes[i]){
(toPush)->ePartIdx = i;
}
if ((toPush)->start == connectTypes[i]){
(toPush)->sPartIdx = i;
}
}
(*toPush).len = (int) strtol(len, &noneDigit, BASE_10);
(*toPush).price = (int) strtol(price, &noneDigit, BASE_10);
//push the new node
toPush->nextPart = headPart;
headPart = toPush;
}
here's a documentation of the debugger, showing the memory loss i described
clear & informative debugger overview
Why am i losing this memory if i allocated it in the heap?
what should i do in order to handle the behavior?
Edit: issue fixed, but now i encounter a circle in my linked list - It seems that the computer doesn't remember it already allocated certain parts of the memory and it allocates it again. as you can see, at the 4th iteration, a not in use memory is being allocated, but after reading the sscanf line it changes it's address. how is this possible?
circle in linked list
I have a struct that has a BST of vertices within it (nodes called vertex). Each vertex has a char array name. I'm working on a function that gets all the vertex names and stores them in an array.
I feel like this should be working, but when testing I'm getting "memory clobbered past end of allocated block". I'm newer to C, and I've debugged a lot and can't surely determine which variable or where this is getting thrown. Any help would be appreciated!
I have narrowed it down so that I know this error is getting thrown somewhere in fill_vertices_array() once it is called from get_vertices(), but I can't narrow it down any more to a certain variable or recursion.
char **get_vertices(Graph graph) {
int num_verts = num_vertices(graph);
/* use a pointer so recursive calls won't effect incrementation */
int *i = malloc(sizeof(*i));
/* allocate space for all vertices plus 1 for the null index */
char **vertices = (char **)malloc((num_verts + 1) * sizeof(char *));
*i = 0;
/* fill with vertices */ /* CLOBBERING HAPPENING SOMEWHERE IN BELOW CALL */
fill_vertices_arr(vertices, i, graph.vertex);
/* save NULL as the last index */
vertices[num_verts] = NULL;
return vertices;
}
void fill_vertices_arr(char **vertices, int *start_index, Vertex *vertex) {
if (vertex != NULL) {
/* in-order traversal, adding to array */
fill_vertices_arr(vertices, start_index, vertex->left);
vertices[*start_index] = (char *)malloc(strlen(vertex->name) * sizeof(char));
strcpy(vertices[*start_index], vertex->name);
(*start_index) += 1;
fill_vertices_arr(vertices, start_index, vertex->right);
}
}
Note: In my test, I have added 8 vertices, and this has succeeded, so it has 8, each with a name. When I then run "char **names = get_vertices(graph)" I get the clobber error.
I want to read users input combined of strings and numbers, like this:
50:string one
25:string two blablabla
...
I don't know how many of the lines the input will have and I also don't know maximum length of the strings.
So I created
typdedef struct line
{
int a
char *string
} line;
Then an array of this sturct
line *Array = NULL;
Now I have a cycle, that reads one line and parses it to temporaryString and temporaryA. How can I realloc the Array to copy these into the array?
There are two valid options to do what you want:
1) use the realloc() function; it's like malloc and calloc but you can realloc your memory, as the name can advise;
2) use a linked list;
The second is more complex than the first one, but is also really valid. In your case, a simple linked list could have the form:
typdedef struct line
{
int a;
char *string;
line *next;
//line *prev;
} line;
Everytime you add a node, you have to alloc a struct line with your new data, set next pointer to NULL or to itself, it's the same, and set the previous next pointer to the new data you created. That's a simpy method to do manually a realloc. The prev pointer is needed only if you need to go from the last item to the first; if you don't need this feature, just save the root pointer (the first one) and use only next pointer.
You could something like this (pseudo code).
idx = 0;
while (input = read()) {
temporaryString, temporaryA = parse(input);
Array = realloc(Array, (idx + 1)*sizeof(line));
Array[idx].a = temporaryA;
Array[idx].string = malloc(strlen(temporaryString) + 1);
strcpy(Array[idx].string, temporaryString);
idx++;
}
On RHEL6, I'm facing a strange problem with realloc(). At some point in the program, realloc() returns NULL (the old pointer has an address and there's plently of memory available). What's being allocated is 200 structure elements (structure below). For some reason, when I do a realloc() instead, it works, but I then have to assign the old pointer to the new one. Below is a simplified version of my code.
This is perhaps a server tuning issue more than a programming one. What is your opinion?
Thanks.
//hearder file
typedef struct { /* Variable Node Detail Record */
long next;
long mask;
char *value;
// more stuff...
} NODETEST;
extern NODETEST *oldNodes;
extern NODETEST *newNodes;
//program
#define MAXSIZE 200
// do some stuff with oldNodes....
int alloc_nodes (void)
{
// Allocate or grow the table
oldNodes = (NODETEST *) malloc(MAXSIZE * sizeof(NODETEST));
if( oldNodes == NULL ) {
//handle exception...
exit(1);
}
//oldNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** FAILS
newNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** WORKS
if( newNodes == NULL ){
printf("errno=%d\n", errno );
}else{
oldNodes = newNodes; }
}
Your first call malloc with a size S and then realloc with the same size S. This is wrong: you have to pass to realloc the new wanted size (independently of the current size - it is not an increment). Here, there is a big chance realloc returns exactly the same pointer it received. BTW it is not clear why you want to do with a malloc immediately followed by a realloc. Gives us more detail.
If you want a dynamic table whose size auto-adjusts, you need to allocate an initial size storing its size in a variable (e.g. alloc_size) and keep the current number of occupied elements in another variable (e.g. n_elem) . When you add an element you increment this number. When the table is full reallocate it. Here is a sketch
NODETEST *newNodes = NULL;
int allocated_elem = 0;
int n_elem = 0;
#define ALLOC_INCR 200
then at each addition:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size += ALLOC_INCR;
nodes = (NODETEST *) realloc(nodes, alloc_size * sizeof(NODETEST));
if (nodes == NULL) {
//handle exception...
exit(1);
}
}
// add your element at nodes[n_elem]
n_elem++;
Recall that realloc acts like malloc when the received pointer is NULL (case of the first call). Thus it allocates the initial table. Subsequent calls reallocate it by adjusting the size with a constant increment (here 200). Some other schemes are possible for the enlargement of the table, for instance you can multiply the size by a factor (e.g. 2) starting from 32:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size = (alloc_size == 0) ? 32 : alloc_size * 2;
Regarind the FAIL and WORKS comments: it is clear that if you assign oldNodes (in the FAIL code) then newNodes is not assigned and keeps its initial value which is zero (NULL) since it is declared as a global variable and not initialized (well I suppose, it is extern here). Thus the test if (newNodes == NULL) will probably fail.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Parsing text in C
Say I have written to a text file in this format:
key1/value1
key2/value2
akey/withavalue
anotherkey/withanothervalue
I have a linked list like:
struct Node
{
char *key;
char *value;
struct Node *next;
};
to hold the values. How would I read key1 and value1? I was thinking of putting line by line in a buffer and using strtok(buffer, '/'). Would that work? What other ways could work, maybe a bit faster or less prone to error? Please include a code sample if you can!
Since your problem is a very good candidate for optimizing memory fragmentation, here is an implementation that uses some simple arcane magic to allocate all strings and the structure itself in a single piece of memory.
When destroying the node, you need only a single call to free(), to the node itself.
struct Node *list = NULL, **nextp = &list;
char buffer[1024];
while (fgets(buffer, sizeof buffer, file) != NULL) {
struct Node *node;
node = malloc(sizeof(struct Node) + strlen(buffer) + 1);
node->key = strtok(strcpy((char*)(node+1), buffer), "/\r\n");
node->value = strtok(NULL, "\r\n");
node->next = NULL;
*nextp = node;
nextp = &node->next;
}
Explanation:
With 20 comments and one unexplained downvote, I think that the code needs some explanation, specially with regards to the tricks employed:
Building a linked list:
struct Node *list = NULL, **nextp = &list;
...
*nextp = node;
nextp = &node->next;
This is a trick to create a linked list iteratively in forward order without having to special-case the head of the list. It uses a pointer-to-pointer to the next node. First the nextp pointer points to the list head pointer; in the first iteration, the list head is set through this pointer-to-pointer and then nextp is moved to the next pointer of that node. Subsequent iterations fill the next pointer of the last node.
Single allocation:
node = malloc(sizeof(struct Node) + strlen(buffer) + 1);
node->key = ... strcpy((char*)(node+1), buffer) ...
We have to deal with three pointers: the node itself, the key string and the value string. This usually would require three separate allocations (malloc, calloc, strdup...), and consequently free separate releases (free). Instead, in this case, the spaces of the tree elements are summed in sizeof(struct Node) + strlen(buffer) + 1 and passed to a single malloc call, which returns a single block of memory. The beginning of this block of memory is assigned to node, the structure itself. The additional memory (strlen(buffer)+1) comes right after the node, and it's address is obtained using pointer arithmetic using node+1. It is used to make a copy of the entire string read from the file ("key/value\n").
Since malloc is called a single time for each node, a single allocation is made. It means that you don't need to call free(node->key) and free(node->value). In fact, it won't work at all. Just a single free(node) will take care of deallocating the structure and both strings in one block.
Line parsing:
node->key = strtok(strcpy((char*)(node+1), buffer), "/\r\n");
node->value = strtok(NULL, "\r\n");
The first call to strtok returns the pointer to the beginning of the buffer itself. It looks for a '/' (additionally for end-of-line markers) and breaks the string there with a NUL character. So the "key/value\n" is broken in "key" and "value\n" with a NUL character in between, and a pointer to the first is returned and stored in node->key. The second call to strtok will work upon the remaining "value\n", strip the end-of-line marker and returning a pointer to "value", which is stored in node->value.
I hope this cleans all questions about the above solution... it is too much for a closed question. The complete test code is here.
You could also use fscanf to parse the input lines directly into keys and values:
char key[80], value[80];
fscanf (pFile, "%s/%s", key, value);
However, the drawback of this approach is that you need to allocate big enough buffers for the keys and values in advance (or use a temp buffer, then copy its value into its final destination, allocated with the right size). With strtok you can check the length of each key and value, then allocate a buffer of exactly the right size to store it.
Update: As commenters pointed out, another (potentially more serious) drawback of fscanf is that it doesn't work for strings containing whitespace.
If you wouldn't mind having aboth the key and the walue in one memory block (two strings), you can just read into a buffer, find the '/' change it into '\0' and point the value pointer just behind the '\0' character. Just don't forget to call free() only on the key value (this will free both the key and the value).
cycle through lines:
1) find '/'
2) devide pair key/value at the position '/'
3) fill key and value
in code:
char* p;
if(p = strchr(str,'/')
{
*p++ = 0;
key = strdup(str);
value = strdup(p);
}