Originally Posted by
barracuda
I want to mark few positions in string so I can simple access them. I mean not to save int but the pointer to the corresponding position.
Define a suitable mark structure. Note that instead of a pointer to end, it's easier to use length, as then you can use e.g. strncmp("name", name, name_len) to compare such. (Besides, name_end = name + name_len anyway.)
Here is an example:
Code:
typedef struct {
const char *name;
size_t name_len;
const char *value;
size_t value_len;
} pair;
Although you can just use a pair with name=NULL, name_len=0, value=NULL, value_len=0 as the end-of-array pair, checking all four to detect it is a bit tedious, so I'd define a pair array structure with the array size counter, so no such special pairs are needed:
Code:
typedef struct {
size_t items;
pair *item;
} pair_array;
If you often append new elements to an array, you might wish to use two counters instead, one for the number of elements you've allocated memory for in item, and the other for the actual item count (like items above).
Your arguments would then be just an array of pair arrays. You could use a special pair array ( items=0, item=NULL ) as an end of arguments marker, but I think a counter is better. Assuming these are global parameters, you can just make them global variables:
Code:
size_t arguments;
pair_array *argument;
Assuming you've done all the allocations, and the indexes are within the allocated limits, you could then access them using
Code:
/* Assuming (arguments > 5) && (argument[5]->items > 3) */
argument[5].item[3].name
argument[5].item[3].name_len
/* (argument[5].item[3].name + argument[5].item[3].name_len) is the end pointer */
argument[5].item[3].value
argument[5].item[3].value_len
/* (argument[5].item[3].value + argument[5].item[3].value_len) is the end pointer */
Technically, this is three-star code; we have pointer (argument) to pointer (item) to pointer (name, or value), but having dedicated types or structures makes it pretty readable.
Dynamic memory management for these is simple:
Code:
/* Return a pointer to pair p in argument a,
* extending the arrays as needed.
*/
pair *get_pair(const size_t a, const size_t p)
{
if (a >= arguments) {
argument = realloc(argument, (a + 1) * sizeof *argument);
if (new_array == NULL) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
while (arguments <= a) {
argument[arguments].items = 0;
argument[arguments].item = NULL;
arguments++;
}
}
{
pair_array *const array = argument + a;
if (p >= array->items) {
array->item = realloc(array->item, (p + 1) * sizeof *array->item);
if (array->item == NULL) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
while (array->items <= p) {
array->item[array->items].name = NULL;
array->item[array->items].name_len = 0;
array->item[array->items].value = NULL;
array->item[array->items].value_len = 0;
array->items++;
}
}
return array + a;
}
}
with quite simple usage,
Code:
pair *p;
p = get_pair(5, 3);
/* p->name == argument[5].item[3].name
* p->name_len == argument[5].item[3].name_len
* p->value == argument[5].item[3].value
* p->value_len == argument[5].item[3].value_len
*/
Since get_pair() aborts the program in case reallocation fails, there is no need to worry about freeing the old arrays, as the OS/kernel will handle that for us.
In case you wonder, (argument + a) is just a simpler way to write "pointer to element a in argument", &(argument[a]).