Thread: I'm donating my vector lib.

  1. #1
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587

    I'm donating my vector lib.

    It(vector.h and vector.c) is hereby released to the public domain.

    I've ended up with a rather complete vector library, is there any functionality I'm missing? General opinions(be nice), constructive criticism, tips/pointers, improvements?

    UPDATE(6/24/10): Added negative indexes, -1 being the last positive index, and -2 being second to last, the pattern continues... Major naming scheme change. The name "vector" is no longer used.

    vector.h
    Code:
    #ifndef VECTOR_H_INCLUDED
    #define VECTOR_H_INCLUDED
    #ifdef _cplusplus
    extern "C"{
    #endif
    
    struct sll_t{
    	int elem;
    	int size;
    	struct data_node *data;
    };
    
    const struct sll_t *sll_init(int size); /* Initializes a sll_t to hold the specified size */
    
    const void *sll_read_data(const struct sll_t *ll, int index); /* Returns a pointer to the data stored at "index" offset in sll_t "ll" */
    const void *sll_write_data(const struct sll_t *ll, int index, void *data); /* Stores a pointer to dynamically allocated copy of "data" at "index" offset in sll_t "ll" */
    
    const void *sll_insert_node(struct sll_t *ll, int index, void *data); /* Inserts a pointer to dynamically allocated copy of "data" at "index" offset in sll_t "ll" */
    const void *sll_append_node(struct sll_t *ll, void *data); /* Wrapper for insert_data with "index" always 0 */
    const void *sll_prepend_node(struct sll_t *ll, void *data); /* Wrapper for insert_data with "index" always the index after last */
    
    int sll_free(struct sll_t *ll); /* Frees a whole sll_t, "ll" */
    int sll_free_range(struct sll_t *ll, int index, int len); /* Frees a range from "index" to "index + len" */
    int sll_free_node(struct sll_t *ll, int index); /* Frees a single node identified with a unique index */
    int sll_trim_start(struct sll_t *ll, int len); /* Wrapper for "free_range" with "index" always 0 */
    int sll_trim_end(struct sll_t *ll, int len); /* Wrapper for "free_range" that frees nodes from the end of the sll_t */
    
    const struct sll_t *sll_copy(const struct sll_t *ll);
    const struct sll_t *sll_merge(struct sll_t *ll, struct sll_t *mergee);
    
    #ifdef _cplusplus
    }
    #endif
    #endif /* VECTOR_H_INCLUDED */
    vector.c
    Code:
    #include <stdlib.h>
    #include <string.h>
    #include "error.h"
    #include "vector.h"
    
    struct data_node{
    	void* data;
    	struct data_node *next;
    };
    
    struct data_node *get_node_extend(struct sll_t *ll, int index); /* These don't need specific typeing because they're not made public */
    struct data_node *get_node_no_extend(struct sll_t *ll, int index);
    
    struct data_node *get_node_extend(struct sll_t *ll, int index)
    {
    	struct data_node *cur_node;
    	cur_node = ll->data; /* Set the current node to the root node */
    	if(index >= 0)
    	{
    		if(ll->elem > index) /* Check to see if the index is within the bounds of the sll_t, if it is, do this the easy way */
    		{
    			cur_node = ll->data;
    			for(;index > 0;index--)
    				cur_node = cur_node->next;
    		}
    		else /* If it's not, do it the hard way */
    		{
    			int c;
    			if(ll->elem == 0) /* Check to see the root node exists */
    			{
    				if((ll->data = cur_node = (struct data_node*)calloc(1, sizeof(struct data_node))) == NULL) /* Allocate memory for it */
    					setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    				cur_node->data = calloc(1, ll->size); /* Allocate memory for it's data */
    					setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    			}
    			for(c = 0;c < index;c++) /* Skip to index */
    			{
    				if((c + 1) >= ll->elem && (c + 1) <= index) /* Does the next node exist, if not... */
    				{
    					if((cur_node->next = (struct data_node*)calloc(1, sizeof(struct data_node))) == NULL) /* Allocate memory for it */
    						setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    					if((cur_node->next->data = calloc(1, ll->size)) == NULL) /* Allocate memory for it's data */
    						setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    				}
    				cur_node = cur_node->next;
    			}
    			if(index >= ll->elem)
    				ll->elem = index + 1;
    		}
    	}
    	else
    		cur_node = get_node_no_extend(ll, index); /* get_data_no_extend has built-in handler for negative indexes */
    	return cur_node;
    }
    
    
    
    struct data_node *get_node_no_extend(struct sll_t *ll, int index)
    {
    	struct data_node *cur_node;
    	cur_node = ll->data; /* Set the current node to the root node */
    	if(index >= 0)
    	{
    		if(ll->elem > index) /* Sanity check */
    		{
    			for(;index;index--) /* Skip to node requested */
    				cur_node = cur_node->next;
    		}
    		else /* Caller tried to access outside bounds, only valid on write */
    		{
    			setlasterr(0, "Referenced non-existant sll_t index", "get_data_no_extend");
    			return NULL;
    		}
    	}
    	else /* Negative indexes start at -1 and increase in distance from the end */
    		if(ll->elem + index >= 0)
    			cur_node = get_node_no_extend(ll, ll->elem + index);
    		else
    			setlasterr(0, "Referenced non-existant sll_t index", "get_data_no_extend");
    	return cur_node;
    }
    
    
    
    const struct sll_t *sll_init(int size)
    {
    	struct sll_t *ll;
    	if((ll = (struct sll_t*)calloc(1, sizeof(struct sll_t))) == NULL) /* Allocate memory for the sll_t structure and check for null pointer*/
    	{
    		setlasterr(0, "Couldn't allocate memory.", "init_vector");
    		return NULL;
    	}
    	if((ll->data = (struct data_node*)calloc(1, sizeof(struct data_node))) == NULL) /* Allocate memory for the root of the linked list of data and check for null pointer*/
    	{
    		setlasterr(0, "Couldn't allocate memory.", "init_vector");
    		return NULL;
    	}
    	ll->elem = 0; /* No elements yet */
    	ll->size = size; /* Size of an element */
    	return ll;
    }
    
    
    
     const void *sll_read_data(const struct sll_t *ll, int index)
    {
    	struct data_node *cur_node;
    	if((cur_node = get_node_no_extend(ll, index)) != NULL)
    		return cur_node->data;
    	else
    	{
    		setlasterr(0, "Referenced non-existant sll_t index", "read_data");
    		return NULL;
    	}
    }
    
    
    
    const void *sll_write_data(const struct sll_t *ll, int index, void *data)
    {
    	return memcpy(get_node_extend(ll, index)->data, data, ll->size);
    }
    
    
    
    const void *sll_insert_node(struct sll_t *ll, int index, void *data)
    {
    	struct data_node *cur_node, *next_node;
    	cur_node = get_node_extend(ll, index);
    	ll->elem++;
    	if((next_node = (struct data_node*)calloc(1, sizeof(struct data_node))) == NULL)
    		setlasterr(0, "Couldn't allocate memory.", "insert_data");
    	next_node->data = cur_node->data;
    	next_node->next = cur_node->next;
    	cur_node->data = memcpy(calloc(1, ll->size), data, ll->size);
    	cur_node->next = next_node;
    	return cur_node->data;
    }
    
    
    
    const void *sll_append_node(struct sll_t *ll, void *data)
    {
    	return sll_insert_node(ll, ll->elem, data);
    }
    
    
    
    const void *sll_prepend_node(struct sll_t *ll, void *data)
    {
    	return sll_insert_node(ll, 0, data);
    }
    
    
    
    int sll_free(struct sll_t *ll)
    {
    	struct data_node *cur_node, *next_node;
    	cur_node = ll->data; /* Set the current node pointer to the root node */
    	for(;ll->elem;ll->elem--)
    	{
    		next_node = cur_node->next; /* Temporarily store the next node in next node while the current node is being freed */
    		free(cur_node); /* Free the current node */
    		cur_node = next_node; /* Set the current node to the next node */
    	}
    	free(ll); /* Free the sll_t structure */
    	return 1;
    }
    
    
    
    int sll_free_range(struct sll_t *ll, int index, int len)
    {
    	struct data_node *cur_node, *next_node, *from;
    	if(((cur_node = get_node_no_extend(ll, index)) != NULL) && index + len <= ll->elem)
    	{
    		int c;
    		from = cur_node;
    		cur_node = cur_node->next;
    		for(c = 1;c < len;c++)
    		{
    			next_node = cur_node->next;
    			free(cur_node);
    			cur_node = next_node;
    		}
    		if((from->next = cur_node) == 0)
    			free(from);
    		else
    		{
    			from->data = cur_node->data;
    			from->next = cur_node->next;
    		}
    		ll->elem -= len;
    		return 1;
    	}
    	else
    	{
    		setlasterr(0, "Attempted to free non-existand sll_t index range.", "free_range");
    		return NULL;
    	}
    }
    
    
    
    int sll_free_node(struct sll_t *ll, int index)
    {
    	struct data_node *cur_node;
    	if(index > 0)
    	{
    		if((cur_node = get_node_no_extend(ll, index - 1)) != NULL)
    		{
    			void* t;
    			t = cur_node->next;
    			cur_node->next = cur_node->next->next;
    			free(t);
    		}
    		else
    		{
    			setlasterr(0, "Attempted to free non-existand sll_t index.", "free_data");
    			return NULL;
    		}
    	}
    	else
    		if(ll->elem > 0)
    			ll->data = ll->data->next;
    		else
    		{
    			setlasterr(0, "Attempted to free non-existand sll_t index.", "free_data");
    			return NULL;
    		}
    	ll->elem--;
    	return 1;
    }
    
    
    
    int sll_trim_start(struct sll_t *ll, int len)
    {
    	return sll_free_range(ll, 0, len);
    }
    
    
    
    int sll_trim_end(struct sll_t *ll, int len)
    {
    	return sll_free_range(ll, ll->elem - len, len);
    }
    
    
    
    const struct sll_t *sll_copy(const struct sll_t *ll)
    {
    	struct data_node *copy_node, *orig_node;
    	struct sll_t *copy = sll_init(ll->size); /* Initialize the sll_t to copy into */
    	if((copy_node = copy->data = calloc(1, sizeof(struct data_node))) == NULL) /* Allocate memory for the root node */
    	{
    		setlasterr(0, "Couldn't allocate memory.", "copy_vector");
    		return NULL;
    	}
    	orig_node = ll->data;
    	for(copy->elem = 0;copy->elem < ll->elem;copy->elem++)
    	{
    		if((copy_node->data = malloc(copy->size)) == NULL) /* Allocate memory for to data is this node */
    		{
    			setlasterr(0, "Couldn't allocate memory.", "copy_vector");
    			return NULL;
    		}
    		memcpy(copy_node->data, orig_node->data, ll->size); /* Copy data from original */
    		if((copy_node->next = calloc(1, sizeof(struct data_node))) == NULL) /* Allocate next data node */
    		{
    			setlasterr(0, "Couldn't allocate memory.", "copy_vector");
    			return NULL;
    		}
    		copy_node = copy_node->next; /* Advance the node pointers */
    		orig_node = orig_node->next;
    	}
    	return copy;
    }
    Would it be worth the time to add an "insert_vector()" or a "trim_vector()" function?
    Last edited by User Name:; 06-23-2010 at 11:11 PM. Reason: update

  2. #2
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Added some more ways to free vectors and nodes. Changed some names. Is there anything like this for C already?

    Code:
    #ifndef VECTOR_H_INCLUDED
    #define VECTOR_H_INCLUDED
    #ifdef _cplusplus
    /*
     *TODO:
     *C++ class based interface
     */
    extern "C"{
    #endif
    
    struct data_node{
    	void* data;
    	struct data_node *next;
    };
    
    struct vector{
    	int elem;
    	int size;
    	struct data_node *data;
    };
    
    struct vector *init_vector(int size); /* Initializes a vector to hold the specified size */
    
    void *read_data(struct vector *v, int index); /* Returns a pointer to the data stored at "index" offset in vector "v" */
    void *write_data(struct vector *v, int index, void *data); /* Stores a pointer to dynamically allocated copy of "data" at "index" offset in vector "v" */
    
    void *insert_data(struct vector *v, int index, void *data); /* Inserts a pointer to dynamically allocated copy of "data" at "index" offset in vector "v" */
    void *append_data(struct vector *v, void *data); /* Wrapper for insert_data with "index" always 0 */
    void *prepend_data(struct vector *v, void *data); /* Wrapper for insert_data with "index" always the index after last */
    
    int free_vector(struct vector *v); /* Frees a whole vector, "v" */
    int free_range(struct vector *v, int index, int len); /* Frees a range from "index" to "index + len" */
    int free_data(struct vector *v, int index); /* Frees a single node identified with a unique index */
    int free_start(struct vector *v, int len); /* Wrapper for "free_range" with "index" always 0 */
    int free_end(struct vector *v, int len); /* Wrapper for "free_range" that frees nodes from the end of the vector */
    
    #ifdef _cplusplus
    }
    #endif
    #endif /* VECTOR_H_INCLUDED */
    Code:
    #include <stdlib.h>
    #include <string.h>
    #include "error.h"
    #include "vector.h"
    
    struct data_node *get_data_extend(struct vector *v, int index);
    struct data_node *get_data_no_extend(struct vector *v, int index);
    
    struct data_node *get_data_extend(struct vector *v, int index)
    {
    	struct data_node *cur_node, *next_node;
    	cur_node = v->data; /* Set the current node to the root node */
    	if(v->elem > index) /* Check to see if the index is within the bounds of the vector, if it is, do this the easy way */
    	{
    		cur_node = v->data;
    		for(;index > 0;index--)
    			cur_node = cur_node->next;
    	}
    	else /* If it's not, do it the hard way */
    	{
    		int c;
    		if(v->elem == 0) /* Check to see the root node exists */
    		{
    			if((v->data = cur_node = (struct data_node*)calloc(1, sizeof(struct data_node))) == NULL) /* Allocate memory for it */
    				setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    			cur_node->data = calloc(1, v->size); /* Allocate memory for it's data */
    				setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    		}
    		for(c = 0;c < index;c++) /* Skip to index */
    		{
    			if((c + 1) >= v->elem && (c + 1) <= index) /* Does the next node exist, if not... */
    			{
    				if((cur_node->next = (struct data_node*)calloc(1, sizeof(struct data_node))) == NULL) /* Allocate memory for it */
    					setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    				if((cur_node->next->data = calloc(1, v->size)) == NULL) /* Allocate memory for it's data */
    					setlasterr(0, "Couldn't allocate memory.", "get_data_extend");
    			}
    			cur_node = cur_node->next;
    		}
    		if(index >= v->elem)
    			v->elem = index + 1;
    	}
    	return cur_node;
    }
    
    struct data_node *get_data_no_extend(struct vector *v, int index)
    {
    	struct data_node *cur_node;
    	cur_node = v->data; /* Set the current node to the root node */
    	if(v->elem > index) /* Sanity check */
    	{
    		for(;index;index--) /* Skip to node requested */
    			cur_node = cur_node->next;
    		return cur_node;
    	}
    	else /* Caller tried to access outside bounds, only valid on write */
    	{
    		setlasterr(0, "Referenced non-existant vector index", "get_data_no_extend");
    		return NULL;
    	}
    }
    
    struct vector *init_vector(int size)
    {
    	struct vector *v;
    	if((v = (struct vector*)calloc(1, sizeof(struct vector))) == NULL) /* Allocate memory for the vector structure and check for null pointer*/
    	{
    		setlasterr(0, "Couldn't allocate memory.", "init_vector");
    		return NULL;
    	}
    	if(v->data = (struct data_node*)calloc(1, sizeof(struct data_node)) == NULL) /* Allocate memory for the root of the linked list of data and check for null pointer*/
    	{
    		setlasterr(0, "Couldn't allocate memory.", "init_vector");
    		return NULL;
    	}
    	v->elem = 0; /* No elements yet */
    	v->size = size; /* Size of an element */
    	return v;
    }
    
    void *read_data(struct vector *v, int index)
    {
    	struct data_node *cur_node;
    	if((cur_node = get_data_no_extend(v, index)) != NULL)
    		return cur_node->data;
    	else
    	{
    		setlasterr(0, "Referenced non-existant vector index", "read_data");
    		return NULL;
    	}
    }
    
    void *write_data(struct vector *v, int index, void *data)
    {
    	return memcpy(get_data_extend(v, index)->data, data, v->size);
    }
    
    void *insert_data(struct vector *v, int index, void *data)
    {
    	struct data_node *cur_node, *next_node;
    	cur_node = get_data_extend(v, index);
    	v->elem++;
    	if((next_node = (struct data_node*)calloc(1, sizeof(struct data_node))) == NULL)
    		setlasterr(0, "Couldn't allocate memory.", "insert_data");
    	next_node->data = cur_node->data;
    	next_node->next = cur_node->next;
    	cur_node->data = memcpy(calloc(1, v->size), data, v->size);
    	cur_node->next = next_node;
    	return cur_node->data;
    }
    
    void *append_data(struct vector *v, void *data)
    {
    	return insert_data(v, v->elem, data);
    }
    
    void *prepend_data(struct vector *v, void *data)
    {
    	return insert_data(v, 0, data);
    }
    
    int free_vector(struct vector *v)
    {
    	struct data_node *cur_node, *next_node;
    	cur_node = v->data; /* Set the current node pointer to the root node */
    	for(;v->elem;v->elem--)
    	{
    		next_node = cur_node->next; /* Temporarily store the next node in next node while the current node is being freed */
    		free(cur_node); /* Free the current node */
    		cur_node = next_node; /* Set the current node to the next node */
    	}
    	free(v); /* Free the vector structure */
    }
    
    int free_range(struct vector *v, int index, int len)
    {
    	struct data_node *cur_node, *next_node, *from;
    	if(((cur_node = get_data_no_extend(v, index)) != NULL) && index + len <= v->elem)
    	{
    		int c;
    		from = cur_node;
    		cur_node = cur_node->next;
    		for(c = 1;c < len;c++)
    		{
    			next_node = cur_node->next;
    			free(cur_node);
    			cur_node = next_node;
    		}
    		if((from->next = cur_node) == 0)
    			free(from);
    		else
    		{
    			from->data = cur_node->data;
    			from->next = cur_node->next;
    		}
    		v->elem -= len;
    		return 1;
    	}
    	else
    	{
    		setlasterr(0, "Attempted to free non-existand index range.", "free_range");
    		return NULL;
    	}
    }
    
    int free_data(struct vector *v, int index)
    {
    	struct data_node *cur_node;
    	if(index > 0)
    	{
    		if((cur_node = get_data_no_extend(v, index - 1)) != NULL)
    		{
    			void* t;
    			t = cur_node->next;
    			cur_node->next = cur_node->next->next;
    			free(t);
    		}
    		else
    		{
    			setlasterr(0, "Attempted to free nonexistand vector node.", "free_data");
    			return NULL;
    		}
    	}
    	else
    		if(v->elem > 0)
    			v->data = v->data->next;
    		else
    		{
    			setlasterr(0, "Attempted to free nonexistand vector node.", "free_data");
    			return NULL;
    		}
    	v->elem--;
    	return 1;
    }
    
    int free_start(struct vector *v, int len)
    {
    	return free_range(v, 0, len);
    }
    
    int free_end(struct vector *v, int len)
    {
    	return free_range(v, v->elem - len, len);
    }

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by User Name: View Post
    Is there anything like this for C already?
    Dunno, but you could check here (and/or send it to them):
    ccan
    Apparently a very new effort at a worthwhile resource.

    My own take on why/why not existing libs WRT C is that the syntax favours tailored custom structures over generic ones. Eg, I have not looked at your code, not because I think it is bad or useless, but because if I need something like this I will just write something (or adopt something I've already written) to do exactly what I need doing and nothing more.

    An analogy: there is no "linked list" type altho linked lists are very commonly used in C. So why not a generic linked list lib? Well, the last time I needed one it took me ~ 10 min to write the three or four functions I needed, which is less time than it would take me to learn a generic library, and it's almost certainly more efficient because it does not involve concerns not pertinent to the situation.

    This is not to say you are wasting your time! Check out that CCAN site.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Error 7 error C2440: '=' : cannot convert from 'bool' to 'data_node *' g:\application data2\visual studio 2008\projects\temp\temp5.cpp 111
    Error 1 error C3861: 'setlasterr': identifier not found g:\application data2\visual studio 2008\projects\temp\temp5.cpp 65
    Error 3 error C4716: 'free_vector' : must return a value g:\application data2\visual studio 2008\projects\temp\temp5.cpp 175
    Warning 1 warning C4101: 'next_node' : unreferenced local variable g:\application data2\visual studio 2008\projects\temp\temp5.cpp 53
    Last edited by Elysia; 06-23-2010 at 02:03 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Well, the last time I needed one it took me ~ 10 min to write the three or four functions I needed, which is less time than it would take me to learn a generic library,
    That works in most cases and would have worked for me, but my OCD wants extensible, large, infrastructure, so it gets extensible, large, infrastructure . I tend to do this type of thing even for the smallest toy projects. You should be my scatter brained code for my OS. I've got a partial driver API, a physical page allocator, but no virtual allocator or byte-size allocator.

    The cool thing about my vector lib is how it allocates automatically on write, but will fail(and setlasterr()) on a read from an uninitialized index.

    Error 7 error C2440: '=' : cannot convert from 'bool' to 'data_node *' g:\application data2\visual studio 2008\projects\temp\temp5.cpp 111
    I don't get this one, there's a brace on 111.
    Error 1 error C3861: 'setlasterr': identifier not found g:\application data2\visual studio 2008\projects\temp\temp5.cpp 65
    setlasterr is in another lib I wrote.
    Error 3 error C4716: 'free_vector' : must return a value g:\application data2\visual studio 2008\projects\temp\temp5.cpp 175
    Oops. Fixed it now.
    Warning 1 warning C4101: 'next_node' : unreferenced local variable g:\application data2\visual studio 2008\projects\temp\temp5.cpp 53
    Another dumb mistake.

    I'll be using -Wall from now on.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's this line:
    Code:
    	if((v = (struct vector*)calloc(1, sizeof(struct vector))) == NULL) /* Allocate memory for the vector structure and check for null pointer*/
    Make sure to add parenthesises to avoid this error (as shown).
    Also, possibly use assert instead of failing on uninitialized index read.
    And you need to include setlasterr to make sure people can use this without dependencies.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    By fail, I mean return NULL.

    error.h
    Code:
    #ifndef ERROR_H_INCLUDED
    #define ERROR_H_INCLUDED
    
    int getlasterrno();
    char *getlasterrfunc();
    char *getlasterrstr();
    void setlasterr(int errno, char *errstr, char *errfunc);
    
    #endif /* ERROR_H_INCLUDED */
    error.c
    Code:
    #include <stdlib.h>
    #include <string.h>
    #include "error.h"
    
    int lasterrno;
    char *lasterrfunc;
    char *lasterrstr;
    
    int getlasterrno()
    {
    	return lasterrno;
    }
    
    char *getlasterrfunc()
    {
    	return lasterrfunc;
    }
    
    char *getlasterrstr()
    {
    	return lasterrstr;
    }
    
    void setlasterr(int errno, char *errstr, char *errfunc)
    {
    	lasterrno = errno;
    	lasterrfunc = strcpy(malloc(strlen(errfunc) + 1), errfunc);
    	lasterrstr = strcpy(malloc(strlen(errstr) + 1), errstr);
    }
    Make sure to either add C++ exterc "C" guards or compile as C, I noticed "temp5.cpp" last time. I don't think it will link right if you don't.

  8. #8
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Just fixed the missing paren thing. Funny how I got it right on the same thing right above it.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    This is problematic. You aren't checking the return-value of malloc.
    And seeing your setlasterr function, you have another problem:
    Warning 1 warning C6011: Dereferencing NULL pointer 'next_node': Lines: 146, 147, 148, 149, 150, 151 g:\application data2\visual studio 2008\projects\temp\temp5.cpp 151
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Shouldn't this be on the project board?

    I have some beefs with the API. There's hardly "const" in there for one, returning "char *" from getlasterrfunc() implies I can modify it.

    Code:
    setlasterr(0, "example", "example");
    setlasterr(0, "example", "example");
    Causes a memory leak, why!?

    What if I want more than INT_MAX elements in the vector? Too bad? Why not allow at least the max of size_t elements?

    The fact you haven't prefixed your functions with "vector_" or alike most likely means users will see clashes with their own functions. "free_data()" is one example. Why aren't you using "static" more? I don't see why your globals need external linkage.

  11. #11
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    I don't know why you call it vector, I just see it as a linked list! LOL
    Probably do_foreach( ) ?
    Code:
    struct vector{
        int elem;
        int size;               // sizeof element use size_t
        struct data_node *data;
    };
    How about negative index? -1 for last item? etc?
    dup_vec()? that will make a new copy of vector?
    Then you can do something like say
    new_vec = do_foreach( dup_vec(orig_vec) ,apply_function,NULL );

  12. #12
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    I'm not sure it's wise to expose the implementation of "struct vector", i.e. in the header file. Once it's done, it's stuck. The user is also "free" to change elements of the structure on their own, without any mediation of your functions.

    I've attached a basic generic linked list that I wrote a while ago, it might give you ideas. Note how I give the user a chance to free their data before I destroy the node.
    Last edited by zacs7; 06-23-2010 at 07:31 PM.

  13. #13
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    setlasterr() patch:
    Code:
    	lasterrno = errno;
    	if(lasterrfunc != NULL)
    		free(lasterrfunc);
    	if(lasterrstr != NULL)
    		free(lasterrstr);
    	if((lasterrfunc = malloc(strlen(errfunc) + 1)) != NULL)
    		strcpy(lasterrfunc, errstr);
    	if((lasterrstr = malloc(strlen(errstr) + 1)) != NULL)
    		strcpy(lasterrstr, errstr);
    I'm working on a copy function, and if it isn't too hard, I'm going to do a merge too. I'm also going back through to use more correct types.

  14. #14
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Here's a duplicating function:
    Code:
    const struct vector *copy_vector(struct vector *v)
    {
    	struct data_node *copy_node, *orig_node;
    	struct vector *copy = init_vector(v->size); /* Initialize the vector to copy into */
    	if((copy_node = copy->data = calloc(1, sizeof(struct data_node))) == NULL) /* Allocate memory for the root node */
    	{
    		setlasterr(0, "Couldn't allocate memory.", "copy_vector");
    		return NULL;
    	}
    	orig_node = v->data;
    	for(copy->elem = 0;copy->elem < v->elem;copy->elem++)
    	{
    		if((copy_node->data = malloc(copy->size)) == NULL) /* Allocate memory for to data is this node */
    		{
    			setlasterr(0, "Couldn't allocate memory.", "copy_vector");
    			return NULL;
    		}
    		memcpy(copy_node->data, orig_node->data, v->size); /* Copy data from original */
    		if((copy_node->next = calloc(1, sizeof(struct data_node))) == NULL) /* Allocate next data node */
    		{
    			setlasterr(0, "Couldn't allocate memory.", "copy_vector");
    			return NULL;
    		}
    		copy_node = copy_node->next; /* Advance the node pointers */
    		orig_node = orig_node->next;
    	}
    	return copy;
    }
    I love the idea of a for_each type function, but I'm not sure if I can figure out how to implement it. I'll try. I'm having a problem with making everything const, I get all kinds of errors for trying to modify the vector structures. How do I cast away const-ness?

  15. #15
    Registered User creek23's Avatar
    Join Date
    Jun 2010
    Location
    Philippines
    Posts
    17
    Try releasing it in LGPL license, so anyone who will use and made fixes and additional functionality will have to re-release the _updated_ one.

Popular pages Recent additions subscribe to a feed