Problems with Pointers

S

stevenruiz

Hello All

My question mainly is how to use/reference Double Pointers? I am
currently trying to understand what the meaning of a 'vector of
pointers' means also? What I am trying to do is take a char array and
break it up into words omitting the spaces. What needs to be noted is
that I am trying to accomplish this only using char ** and char *.
Therefore, I am creating it from scratch. Below is code that I have
written so far:

int main()
{
char input[125] = " Hello World\0"
char **doublePointer;
char *receiveArray;

doublePointer = malloc(125 * sizeof(char *));
receiveArray = input;

int i;
for(i = 0; receiveArray [ i ] != '\0'; i++)
{
//Here I am confused
//I'm not sure how to traverse the array and store data into
// the double pointer/vector
//Do I need to do this
// doublePointer [ i ] = malloc ( sizeof( char * ));
}


free(doublePointer);

return 0;
}

Any hints and suggestions about the algorithm/design would be
welcome. Thanks.
 
B

Ben Bacarisse

My question mainly is how to use/reference Double Pointers? I am
currently trying to understand what the meaning of a 'vector of
pointers' means also? What I am trying to do is take a char array and
break it up into words omitting the spaces. What needs to be noted is
that I am trying to accomplish this only using char ** and char *.
Therefore, I am creating it from scratch. Below is code that I have
written so far:

Why start with main? What function would really, really help to solve
this? Image it exists and take it from there. Then all you need do
is write that now slightly simpler function.

Personally, I want a function declared like this:

char *next_word(const char **string);

/* Returns a pointer to a copy (in malloc'd storage) of the
* next word found in *string. *string is updated to point to
* first character found that is not part of the work returned.
* If no word is found, NULL is returned.
*/

With this function in the bag, I'd expect to see a relatively simple
loop, putting the returned pointers into elements of a char * array.
For bonus marks, I'd hope to see a loop that reallocs this array if
more words than expected are found.

Now you just need to write next_word. What function would really,
really help to write next_word? Image it exists and take it from
there...
int main()
{
char input[125] = " Hello World\0"
char **doublePointer;
char *receiveArray;

doublePointer = malloc(125 * sizeof(char *));

If you are going to use 125, just declare

char *doublePointer[125];

BTW, that is a terrible name! Name you variables with what that mean
(usually what they contain) not what type they have.
receiveArray = input;

int i;
for(i = 0; receiveArray [ i ] != '\0'; i++)
{
//Here I am confused
//I'm not sure how to traverse the array and store data into
// the double pointer/vector
//Do I need to do this
// doublePointer [ i ] = malloc ( sizeof( char * ));

I would not start in the middle of a loop in main, sorry.
 
B

Barry Schwarz

Hello All

My question mainly is how to use/reference Double Pointers? I am
currently trying to understand what the meaning of a 'vector of
pointers' means also? What I am trying to do is take a char array and

The phrase has no defined meaning in the standard. Since the word
vector also has no special meaning in C, I would take the phrase to be
synonymous with "array of pointers".
break it up into words omitting the spaces. What needs to be noted is

Define break it up.

Do you want to replace the word separators (usually a space)
with '\0' so that the array now contains multiple strings, each
corresponding to a word? If so, do you want to build an array of
pointers that points to each word?

Or do you want to copy the portions of the string that
constitute words to new arrays of char? If so, do you want the
resulting arrays to contain valid strings or just the characters in
the words? Do you want to define the target arrays or dynamically
allocate them?
that I am trying to accomplish this only using char ** and char *.

This is probably adequate for this task but why would you arbitrarily
limit yourself to a subset of the language? Usually arbitrary
restrictions like this are a sure sign of homework.
Therefore, I am creating it from scratch. Below is code that I have
written so far:

Writing code before the intent is defined is perilous.
int main()
{
char input[125] = " Hello World\0"
char **doublePointer;
char *receiveArray;

doublePointer = malloc(125 * sizeof(char *));

Do you really think you will need a char* for char in input?
receiveArray = input;

int i;
for(i = 0; receiveArray [ i ] != '\0'; i++)
{
//Here I am confused
//I'm not sure how to traverse the array and store data into
// the double pointer/vector

Until you decide what data to store in the space pointed to by
doublePointer, we will be unsure also.
//Do I need to do this
// doublePointer [ i ] = malloc ( sizeof( char * ));

This is definitely wrong. doublePointer is a char**. Therefore
doublePointer is a char*. If you want doublePointer to point to
dynamically allocated memory, the argument passed to malloc should
always be the (maximum) number of characters you intend to store in
that memory. On most system, your code would limit you to 4 or 8.
This is the reason that many here recommend the following syntax for
allocating a dynamic array to a pointer named x:
x = malloc(number_of_elements_desired * sizeof *x);
}


free(doublePointer);

If doublePointer and all the doublePointer point to allocated
memory, the doublePointer need to be freed before you free
doublePointer.
 
S

stevenruiz

Hello All
My question mainly is how to use/reference Double Pointers? I am
currently trying to understand what the meaning of a 'vector of
pointers' means also? What I am trying to do is take a char array and

The phrase has no defined meaning in the standard. Since the word
vector also has no special meaning in C, I would take the phrase to be
synonymous with "array of pointers".
break it up into words omitting the spaces. What needs to be noted is

Define break it up.

Do you want to replace the word separators (usually a space)
with '\0' so that the array now contains multiple strings, each
corresponding to a word? If so, do you want to build an array of
pointers that points to each word?

Or do you want to copy the portions of the string that
constitute words to new arrays of char? If so, do you want the
resulting arrays to contain valid strings or just the characters in
the words? Do you want to define the target arrays or dynamically
allocate them?
that I am trying to accomplish this only using char ** and char *.

This is probably adequate for this task but why would you arbitrarily
limit yourself to a subset of the language? Usually arbitrary
restrictions like this are a sure sign of homework.
Therefore, I am creating it from scratch. Below is code that I have
written so far:

Writing code before the intent is defined is perilous.


int main()
{
char input[125] = " Hello World\0"
char **doublePointer;
char *receiveArray;
doublePointer = malloc(125 * sizeof(char *));

Do you really think you will need a char* for char in input?
receiveArray = input;
int i;
for(i = 0; receiveArray [ i ] != '\0'; i++)
{
//Here I am confused
//I'm not sure how to traverse the array and store data into
// the double pointer/vector

Until you decide what data to store in the space pointed to by
doublePointer, we will be unsure also.
//Do I need to do this
// doublePointer [ i ] = malloc ( sizeof( char * ));

This is definitely wrong. doublePointer is a char**. Therefore
doublePointer is a char*. If you want doublePointer to point to
dynamically allocated memory, the argument passed to malloc should
always be the (maximum) number of characters you intend to store in
that memory. On most system, your code would limit you to 4 or 8.
This is the reason that many here recommend the following syntax for
allocating a dynamic array to a pointer named x:
x = malloc(number_of_elements_desired * sizeof *x);
free(doublePointer);

If doublePointer and all the doublePointer point to allocated
memory, the doublePointer need to be freed before you free
doublePointer.


return 0;
}


Pretty much what I'm trying to do is create a tokenizer or a (strtok)
and yes I would like to build an array of
pointers that points to each word. This is for I return or print out
to see the words in each position of the array of pointers. I
understand if I were to have a char[] which had, for example, "hello
world\0". The way I have been approaching this is first by
establishing a pointer to that array's first position at the letter
'h' using char *inputData = <the char array>. At this point, I have
the beginning of the char array. Next, I was thinking I would loop
through inputData while it is not equal to a space, I'm thinking that
I would point that doublePointer to that specific address of inputData
[ i ]? Please advise.
 
Z

zaimoni

Pretty much what I'm trying to do is create a tokenizer or a (strtok)
and yes I would like to build an array of
pointers that points to each word.
This is for I return or print out
to see the words in each position of the array of pointers. I
understand if I were to have a char[] which had, for example, "hello
world\0".
Ok.

The way I have been approaching this is first by
establishing a pointer to that array's first position at the letter
'h' using char *inputData = <the char array>. At this point, I have
the beginning of the char array. Next, I was thinking I would loop
through inputData while it is not equal to a space, I'm thinking that
I would point that doublePointer to that specific address of inputData
[ i ]? Please advise.

This is pretty much what strtok does (overwriting the original
character buffer so each token is null-terminated). The main reasons
not to use strtok for this would be that you don't want to overwrite
the incoming text buffer, or that you're reimplementing strtok.
 
Z

zaimoni

Hello All

My question mainly is how to use/reference Double Pointers? I am
currently trying to understand what the meaning of a 'vector of
pointers' means also? What I am trying to do is take a char array and
break it up into words omitting the spaces. What needs to be noted is
that I am trying to accomplish this only using char ** and char *.

As a learning exercise: assume we don't #include said:
Therefore, I am creating it from scratch. Below is code that I have
written so far:

int main()
{
char input[125] = " Hello World\0"

\0 is mostly redundant here. The string literal will implicitly have
a \0 character appended to its representation as an array of
characters.
char **doublePointer;

array_of_c_strings would be a more descriptive name.
char *receiveArray;

doublePointer = malloc(125 * sizeof(char *));
receiveArray = input;

There's an easy rewrite to prepare this for isolating into a function,
but as a concept mockup this works. The rewrite also makes the code
C90-friendly. (right now it's using the C99 feature of intermixing
declarations and code).

In this case, it's a matter of coding style whether to use calloc or
malloc for doublePointer. Due to how things are defined in C, calloc
will automatically set all of the pointers in the dynamically
allocated array to NULL.
int i;
for(i = 0; receiveArray [ i ] != '\0'; i++)
{
//Here I am confused
//I'm not sure how to traverse the array and store data into
// the double pointer/vector

The loop is using i to traverse the array fine. It's what to do that
matters.
//Do I need to do this
// doublePointer [ i ] = malloc ( sizeof( char * ));

i is already being used to traverse receiveArray, so it should not be
used to index into doublePointer. For sake of discussion, assume we
declared another variable

int j = 0;

before entering the loop.

Also, the proposed malloc is mismatched. Once allocated, the "slots"
in the array of char* pointed to by doublePointer will be perfectly
fine to use directly to point to C strings. The malloc expression
would be read as intending to allocate a char** (array of char*), but
doublePointer[j] is of type char* .

Having ruled out strtok as an option, you would be wanting to allocate
an array of char for each token, of length one longer than the
observed token length. As 1==sizeof(char) for standard-compliant
compilers, you could get away with something like the following:

doublePointer[j] = malloc(token_length+1); /* alternately,
malloc((token_length+1)*sizeof(char)) to look like the other malloc */
doublePointer[j][token_length+1] = '\0'; /* plain 0 also works in
place of '\0' */
strncpy(doublePointer[j],receiveArray+i,token_length); /* requires
#include <string.h>, could use a for-loop to hand-roll copying
token_length characters like this */
++j; /* adjust strict upper bound upwards. j++; also works. */

where token_length is some expression you calculated using the other
variables you need to even track being in a strtok-compatible word, as
well as i.
 
Z

zaimoni

(e-mail address removed) said:



No, malloc is the better choice.

As a correct implementation can be explicitly verified to never
inspect the values in the malloc'd array in the first place, malloc is
the objectively better choice; the implied memset call has no
observable effect.

(Regardless of whatever style guidelines that are in force at a
specific locale, and whether portability to platforms from the age of
the computing dinosaurs where the binary representation of NULL is not
all-zero-bits is a concern. Obviously, the following paragraph should
have been qualified with "for typical platforms".)
 
B

Barry Schwarz

As a correct implementation can be explicitly verified to never
inspect the values in the malloc'd array in the first place, malloc is
the objectively better choice; the implied memset call has no
observable effect.

At the very least it wastes time. At the worst, it creates the false
impression that the pointers have been properly initialized.
(Regardless of whatever style guidelines that are in force at a
specific locale, and whether portability to platforms from the age of
the computing dinosaurs where the binary representation of NULL is not
all-zero-bits is a concern. Obviously, the following paragraph should

You really believe that there are no modern systems that can support
accessing location 0? Even when using C to write the operating
system?
 
B

Barry Schwarz

Hello All

My question mainly is how to use/reference Double Pointers? I am
currently trying to understand what the meaning of a 'vector of
pointers' means also? What I am trying to do is take a char array and
break it up into words omitting the spaces. What needs to be noted is
that I am trying to accomplish this only using char ** and char *.

As a learning exercise: assume we don't #include said:
Therefore, I am creating it from scratch. Below is code that I have
written so far:

int main()
{
char input[125] = " Hello World\0"

\0 is mostly redundant here. The string literal will implicitly have
a \0 character appended to its representation as an array of
characters.

The literal, if it exists in the object module, will indeed have a
second '\0' appended to it. The array named input, however, will
consist of 11 characters followed by 114 '\0's independent of whether
there are any '\0's specified or implied in the initialization.
 
C

Chris Torek

Let's start by counting the number of words in the input string ...

[which results in]
size_t wc(const char *s)
{
size_t count = 0;
int state = NOT_IN_WORD;
int space = 0;
while(*s != '\0')
{
space = isspace((unsigned char)*s);
if(state == NOT_IN_WORD && !space)
{
++count;
state = IN_WORD;
}
else if(state == IN_WORD && space)
{
state = NOT_IN_WORD;
}
++s;
}
return count;
}
... now we'd like to point at them. ...
Here, then, is a function to do that. Observe its similarities and
differences with regard to wc() - which it itself calls, by the way:

#include <stdlib.h>
#include <assert.h>
char **wl_build(char *s)
{
int space = 0;
int state = 0;
size_t thisword = 0;
size_t wordcount = wc(s);
char **wl = malloc((wordcount + 1) * sizeof *wl);
if(wl != NULL)
{
while(*s != '\0')
{
space = isspace((unsigned char)*s);
if(state == NOT_IN_WORD && !space)
{
wl[thisword++] = s;
state = IN_WORD;
}
else if(state == IN_WORD && space)
{
*s = '\0'; /* terminate the token */
state = NOT_IN_WORD;
}
++s;
}
wl[thisword] = NULL; /* list is NULL-terminated */
}
assert(thisword == wordcount);
return wl;
}

The alternative to doing this whole state machine thing twice is to count
and reallocate as we go. Possible, and microscopically faster, but perhaps
more effort than we'd like to go to, and the code would be messier, harder
to follow, and harder to maintain.

Given the similarities and differences, I would consider one other
tweak. Suppose we rewrite both wc() and wl_build() in terms of a
third function. This third function is passed a "word list pointer"
value, which may be given as NULL, as well as a string ("s" above)
to split up into words. It counts the words, and -- if and only
if the word-list-pointer is non-NULL -- records and breaks up the
words as well. This results in:

static int wc_and_optionally_build(char *s, char **wl) {
size_t count = 0;
int state = NOT_IN_WORD;
int space = 0;

while (*s != '\0') {
space = isspace((unsigned char)*s);
if (state == NOT_IN_WORD && !space) {
if (wl != NULL) /* record start of token */
wl[count] = s;
count++;
state = IN_WORD;
} else if (state == IN_WORD && space) {
if (wl != NULL)
*s = '\0'; /* terminate the token */
state = NOT_IN_WORD;
}
++s;
}
return count;
}

(I have made this "static" as it is not intended to be used by
any callers other than the two we are about to supply.)

Now we can rewrite both wc() and wl_build() in terms of this third
function, which exposes a slight flaw or two:

size_t wc(const char *s) {
return wc_and_optionally_build((char *)s, NULL);
}

char **wl_build(char *s) {
size_t wordcount = wc(s);
char **wl = malloc((wordcount + 1) * sizeof *wl);

if (wl != NULL) {
size_t repeat = wc_and_optionally_build(s, wl);

assert(repeat == wordcount);
wl[repeat] = NULL;
}
return wl;
}

The first flaw is that we have to "cast away const" in wc(), because
wc_and_optionally_build() *might* write to *s. It does not in fact
write to *s as long as we pass NULL as the second argument.

The second flaw (or perhaps non-flaw) is that this code does not
fail the assert() if the malloc() fails. Instead, this code has
wl_build() return NULL. Richard's version will fail the assert
(unless of course you turn on NDEBUG) for any non-empty word list
(because "wordcount" will be non-zero, but "thisword" will be 0).
The creation of token copies allows us to leave the original string
unmodified ...

and, if you use a third "base" function to "do the real work",
allows one to fix the first flaw.
 
Z

zaimoni

You really believe that there are no modern systems that can support
accessing location 0?

Accessing location zero is different than compiling a program so that
some C entity actually has location zero. E.g., I'd expect location
zero to be accessible (with suitable privileges) in C on an Intel
platform simply because that's the start of the hardware interrupt
vector table. That doesn't mean a C variable or function could
actually be compiled to live there.

As for a compiler placing entities at location zero:
Extant? Sure, such systems exist and remain in use. They don't seem
to be very high on the porting priority list for the FSF, as the use
of calloc to NULL-initialize pointer arrays is explicitly approved in
their portability checklist.

Chronologically new design? I wouldn't be surprised at all, even
though I don't have an example "on tap".

Vaguely modern design? Theoretically possible -- but I'd be surprised
if an example actually existed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top