[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Re: I need help

janus

5/16/2011 11:05:00 AM

>Shao Miller
>
> Sometimes it can be nice to track the length of a string, or a buffer.
> I was a bit bored, so here's something you might or might not enjoy.
> With any luck, it doesn't have any off-by-one errors. :)
>
> Also available at the following link, which has some nice colours:
>
> http://codepad.or...
>
> /* For printf() */
> #include <stdio.h>
> /* For malloc(), free(), EXIT_SUCCESS, EXIT_FAILURE */
> #include <stdlib.h>
> /* For memcpy() */
> #include <string.h>
>
> struct string {
> /*
> * Count of characters in the string,
> * excluding any null terminator, in bytes
> */
> size_t len;
> /* Size of the buffer itself, in bytes */
> size_t max_len;
> /* Points to the buffer */
> char * buf;
> /* For allocation convenience, the buffer can co-incide with this */
> char appended_buf[1];
> };
> /* You can use this macro for [wordy] convenience, as an initializer */
> #define STRING_INIT_FROM_STRING_LITERAL(string) \
> {sizeof string - 1, sizeof string, string, 0}
>
> /* Join non-empty strings with a specified, non-empty delimiter string */
> int join_strings_with_delim(
> struct string * output_str,
> const struct string * const * input_strings,
> const unsigned int input_string_count,
> const struct string * delim,
> int allocation
> ) {
> int i;
> size_t output_size;
> char * buf;
>
> /* Check output string */
> if (!output_str)
> return EXIT_FAILURE;
> /* Check delimiter string */
> if (!delim || !delim->buf || !delim->len)
> return EXIT_FAILURE;
> /* Check the strings to be joined */
> if (!input_string_count || input_string_count < 2 || !input_strings)
> return EXIT_FAILURE;
> for (i = 0, output_size = 0; i < input_string_count; ++i) {
> /* Check each input string */
> if (!input_strings[i] || !input_strings[i]->buf ||
> !input_strings[i]->len)
> return EXIT_FAILURE;
> /* Compute the output size */
> output_size += input_strings[i]->len;
> }
> /* Include the delimiter string size in the computation */
> output_size += delim->len * (input_string_count - 1);
> /* Include the null terminator */
> ++output_size;
> /* Should we allocate? */
> if (allocation) {
> buf = malloc(output_size);
> if (!buf)
> return EXIT_FAILURE;
> output_str->buf = buf;
> output_str->max_len = output_size;
> /* Exclude the null terminator from the string length */
> output_str->len = output_size - 1;
> } else {
> /* We don't allocate, so the caller ought to have */
> if (!output_str->buf || output_size > output_str->max_len)
> return EXIT_FAILURE;
> buf = output_str->buf;
> }
> /* Perform the join */
> i = 0;
> /* Skip the delimiter the first time around */
> goto skip_delim;
> do {
> size_t slen;
> slen = delim->len;
> memcpy(buf, delim->buf, slen);
> buf += slen;
> skip_delim:
> slen = input_strings[i]->len;
> memcpy(buf, input_strings[i]->buf, slen);
> buf += slen;
> ++i;
> } while (i < input_string_count);
> /* Terminate the string */
> *buf = 0;
> return EXIT_SUCCESS;
> }
>
> void free_string_buf(struct string * str) {
> if (!str) {
> /* Programmer error! */
> return;
> }
> free(str->buf);
> str->buf = NULL;
> str->len = str->max_len = 0;
> return;
> }
>
> int main(void) {
> /* These strings don't change, so we use 'static const' */
> static const struct string foo[] = {
> STRING_INIT_FROM_STRING_LITERAL("New York"),
> STRING_INIT_FROM_STRING_LITERAL("New Jersey"),
> STRING_INIT_FROM_STRING_LITERAL("New London"),
> };
> /* An array of pointers to these strings. It oughtn't to change */
> static const struct string * const foo_ptrs[] =
> {foo, foo + 1, foo + 2};
> /* An output string for the joined strings */
> struct string foo_output;
>
> /* Or without the macro, we could have used the more redundant: */
> static const struct string bar[] = {
> {sizeof "New York" - 1, sizeof "New York", "New York", 0},
> {sizeof "New Jersey" - 1, sizeof "New Jersey", "New Jersey", 0},
> {sizeof "New London" - 1, sizeof "New London", "New London", 0},
> };
> /* An array of pointers to these strings. It oughtn't to change */
> static const struct string * const bar_ptrs[] =
> {bar, bar + 1, bar + 2};
> /* An output string for the joined strings */
> struct string bar_output;
>
> /* The delimiter string. It does not change */
> static const struct string delim_str =
> STRING_INIT_FROM_STRING_LITERAL(" ");
>
> /* Track any errors */
> int status;
>
> /*
> * Join the strings, with the specified delimiter,
> * into the output buffer. The number of strings to process
> * can be calculated with 'sizeof array / sizeof *array'.
> * We happen to know that it's 3, but code can change over time
> */
> status = join_strings_with_delim(
> &foo_output,
> foo_ptrs,
> sizeof foo_ptrs / sizeof *foo_ptrs,
> &delim_str,
> 1 /* Allocate the output buffer */
> );
> if (status == EXIT_FAILURE) {
> printf("Allocating foo_output failed!\n");
> return EXIT_FAILURE;
> }
> printf("foo_output: \"%s\"\n", foo_output.buf);
> /* Free the output buffer */
> free_string_buf(&foo_output);
>
> /* Same for 'bar' */
> status = join_strings_with_delim(
> &bar_output,
> bar_ptrs,
> sizeof bar_ptrs / sizeof *bar_ptrs,
> &delim_str,
> 1 /* Allocate the output buffer */
> );
> if (status == EXIT_FAILURE) {
> printf("Allocating bar_output failed!\n");
> return EXIT_FAILURE;
> }
> printf("bar_output: \"%s\"\n", bar_output.buf);
> /* Free the output buffer */
> free_string_buf(&bar_output);
>
> return EXIT_SUCCESS;
> }

I am confuse... Could explain the following;

const struct string * const * input_strings, # Having two consts and pointer symbol staggered

Janus
2 Answers

Shao Miller

5/16/2011 2:26:00 PM

0

On 5/16/2011 07:05, janus wrote:
>> Shao Miller
>> /* Join non-empty strings with a specified, non-empty delimiter string */
>> int join_strings_with_delim(
>> struct string * output_str,
>> const struct string * const * input_strings,
>> const unsigned int input_string_count,
>> const struct string * delim,
>> int allocation
>> ) {
>> int i;
>> size_t output_size;
>> char * buf;
>>
>> /* Check output string */
>> ...
>
> I am confuse... Could explain the following;
>
> const struct string * const * input_strings, # Having two consts and pointer symbol staggered

Absolutely, I'm happy to explain. :)

'input_strings' is a pointer ('*') to a 'const'-qualified pointer ('*')
to a 'const'-qualified 'struct string'.

( [ (const struct string) * const] * input_strings)

What does this madness mean? It means:

- 'input_strings' is not 'const'-qualified, so it can be changed. For
example, you could do:

input_strings++;

- 'input_strings' points to a pointer. _That_ pointer is
'const'-qualified, so it mustn't be changed. For example, you could not do:

input_strings[0] = ...
*input_strings = ...

- 'input_strings' points to a pointer, and _that_ pointer points to a
'struct string'. That 'struct string' is 'const'-qualified, so it
mustn't be changed. For example, you could not do:

input_strings[0][0].len = ...
(*input_strings)[0].len = ...
(*input_strings)->len = ...
(*(*input_strings)).len = ...

Seebs

5/16/2011 7:10:00 PM

0

On 2011-05-16, janus <emekamicro@gmail.com> wrote:
>> const struct string * const * input_strings,

> I am confuse... Could explain the following;

> const struct string * const * input_strings,
> # Having two consts and pointer symbol staggered

cdecl> explain const int * const * foo;
declare foo as pointer to const pointer to const int

What this is doing is saying that the struct strings pointed to
can't be modified, nor can the pointers to them, and input_strings
is an array (in effect) of these unmodifiable pointers.

FWIW, I did length-tracking strings ages ago.

http://www.seebs.net...

I've used them moderately heavily, and not had significant trouble. There's
an obviously unsafe assumption made in them, but In Practice It Works.
It would be pretty trivial to remove it, though it'd impose more bookkeeping.

(Basically, the magic that lets you guess whether something is really one
of these, or just a normal C string, is unreliable.)

-s
--
Copyright 2011, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
http://www.seeb... <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/...(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.