convert string into an array of strings

J

jkelt46

Hi,

I need to take a command line parameter and store it as an array.
i.e. program parameter1 should be stored like this:
wordarray[0]=p
wordarray[1]=a
wordarray[2]=r
wordarray[3]=a
wordarray[4]=m
wordarray[5]=e
etc

or if I do program para1 para2 it should be stored like this:
wordarray[0]=para1
wordarray[1]=para2

The following code works great when I do program para1 para2 however
it doesn't work for program parameter1. When I compile I get
program2c.c:209: warning: assignment makes pointer from integer
without a cast

The reason I use char **wordarray is because the program can take a
variable number parameters.
What am I doing wrong?
Thanks,

int main(int argc, char *argv[]) {
int numleft,temp;
char **wordarray;

numleft=(argc-i)-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[++i];
}
}
else {
numleft=strlen(argv[i+1]);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[i+1][temp]; // line 209
}
}
dowork(wordarray,numleft,0);
}
 
K

Keith Thompson

I need to take a command line parameter and store it as an array.
i.e. program parameter1 should be stored like this:
wordarray[0]=p
wordarray[1]=a
wordarray[2]=r
wordarray[3]=a
wordarray[4]=m
wordarray[5]=e
etc

or if I do program para1 para2 it should be stored like this:
wordarray[0]=para1
wordarray[1]=para2

Your problem statement is unclear. Your first example shows a single
word being split up into individual characters; your second shows each
word being stored in its entirety. Is that really what you want?
Does the behavior change with the number of arguments?

You *might* be trying to do something like this:

If there's one argument
Store each character of the argument in an array element
If there's more than one argument
Store each argument in an array element

but I can't think of any good reason to do that. (And what if there
are no arguments?)
The following code works great when I do program para1 para2 however
it doesn't work for program parameter1. When I compile I get
program2c.c:209: warning: assignment makes pointer from integer
without a cast

No, the following code doesn't work. It doesn't even compile. And if
you're getting a warning on line 209, you obviously haven't shown us
your real code. In any case we can't guess which line the warning is
referring to. (Well, we could guess, but I'm not going to.)
The reason I use char **wordarray is because the program can take a
variable number parameters.
What am I doing wrong?
Thanks,

int main(int argc, char *argv[]) {
int numleft,temp;
char **wordarray;

numleft=(argc-i)-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[++i];
}
}
else {
numleft=strlen(argv[i+1]);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[i+1][temp]; // line 209
}
}
dowork(wordarray,numleft,0);
}

When I compile the code you posted, I get a number of error messages.
You're missing #include directives for <stdio.h>, <stdlib.h>,
<string.h>, and ``i'' and ``dowork'' are undeclared.

Post a small self-contained program and we might be able to help.
 
B

Barry Schwarz

Hi,

I need to take a command line parameter and store it as an array.

All the command line parameters are already stored in arrays. The
first is stored in the array pointed to by argv[1]. What do you want
to do that is different.
i.e. program parameter1 should be stored like this:
wordarray[0]=p
wordarray[1]=a
wordarray[2]=r
wordarray[3]=a
wordarray[4]=m
wordarray[5]=e
etc

In this example, wordarray is obviously an array of char or a pointer
to the first byte of such an array (either defined or allocated). If
the array (or area pointed to) is big enough, you could copy the
command line parameter with strcpy.
or if I do program para1 para2 it should be stored like this:
wordarray[0]=para1
wordarray[1]=para2

In this example, wordarray is obviously an array of pointers or a
pointer to the first pointer in such an array (or much less likely an
array of arrays).

Until you make up your mind which approach you want to use, you
program will always suffer fatal confusion.
The following code works great when I do program para1 para2 however
it doesn't work for program parameter1. When I compile I get
program2c.c:209: warning: assignment makes pointer from integer
without a cast

The reason I use char **wordarray is because the program can take a
variable number parameters.
What am I doing wrong?

Coding before you have thought the problem through? Not cutting and
pasting the program for us to see but retyping it incorrectly?
Ignoring diagnostics from your compiler? Hard to tell with so many
possibilities.
int main(int argc, char *argv[]) {
int numleft,temp;
char **wordarray;

numleft=(argc-i)-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[++i];

Here wordarray is a char**. Hence, wordarray[temp] is a char*. Before
this statement executes, the value in wordarray[temp] was
indeterminate. After this statement, wordarray[temp] points to the
same area of memory that argv[i-1] points to. Since each element of
argv is also a char*, this assignment is acceptable. Of course, you
now have two pointer pointing to the same string but that is a
different issue.
}
}
else {
numleft=strlen(argv[i+1]);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[i+1][temp]; // line 209

wordarray is still a char** and wordarray[temp] is still a char*.
Since argv[i+1] is a char*, argv[i+1][temp] must be char. Why are you
trying to assign a char value to a pointer? What would you expect the
result of such an assignment to be?
 
K

Keith Thompson

I need to take a command line parameter and store it as an array.
int main(int argc, char *argv[]) {
int numleft,temp;
char **wordarray;
numleft=(argc-i)-1;

What's i?

A mistake. It should be removed.

Removing it leaves:

numleft=(argc-)-1;

which is a syntax error. That's obviously not what you meant, but how
are we supposed to guess what you did mean?

You need to post a small self-contained compilable program, or we
can't help you. Don't retype it, copy-and-paste the exact source code
you fed to your compiler. Don't leave anything out, even if you think
it's obvious.
 
J

jkelt46

I need to take a command line parameter and store it as an array.
i.e. program parameter1 should be stored like this:
wordarray[0]=p
wordarray[1]=a
wordarray[2]=r
wordarray[3]=a
wordarray[4]=m
wordarray[5]=e
etc
or if I do program para1 para2 it should be stored like this:
wordarray[0]=para1
wordarray[1]=para2

Your problem statement is unclear.  Your first example shows a single
word being split up into individual characters; your second shows each
word being stored in its entirety.  Is that really what you want?
Does the behavior change with the number of arguments?

You *might* be trying to do something like this:

    If there's one argument
        Store each character of the argument in an array element
    If there's more than one argument
        Store each argument in an array element

but I can't think of any good reason to do that.  (And what if there
are no arguments?)

There will always at least 1 argument. From the responses so far I
must not have explained my problem clearly. I need a variable length
array whose elements point to either a string or a character. I
didn't post the entire program as it would 1573 lines of code.

Here is a working version of the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int numleft, temp;
char **wordarray; /* array to store words */

numleft=argc-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1];
}
}
else {
numleft=(int)strlen(argv[1]);
printf("numleft = %d\n",numleft);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1][temp];
printf("argv[temp+1]temp = %c\n",argv[temp+1][temp]);
}
}
for (temp=0; temp < numleft; temp++) {
printf("wordarray[temp] = %s\n",wordarray[temp]);
}
free(wordarray);
return 0;
}

gcc -Wall help.c -o help
help.c: In function ‘main’:
help.c:29: warning: assignment makes pointer from integer without a
cast

../help dog cat bird
wordarray[temp] = dog
wordarray[temp] = cat
wordarray[temp] = bird

../help dog
numleft = 3
argv[temp+1]temp = d
Segmentation fault
 
B

Ben Bacarisse

From the responses so far I
must not have explained my problem clearly. I need a variable length
array whose elements point to either a string or a character.

Unfortunately, this is still underspecified. Rather than argue over
words, I've "corrected" your code so that it does something that can
be argued matches these words. You can then say in what way I've got
it wrong!
I
didn't post the entire program as it would 1573 lines of code.

Here is a working version of the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int numleft, temp;
char **wordarray; /* array to store words */

numleft=argc-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1];
}
}
else {
numleft=(int)strlen(argv[1]);
printf("numleft = %d\n",numleft);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1][temp];
printf("argv[temp+1]temp = %c\n",argv[temp+1][temp]);

The types here are wrong, as the compiler is telling you. One
interpretation of what you want is to replace these two lines with:

wordarray[temp] = argv[1] + temp;
printf("argv[temp+1]temp = %c\n",argv[1][temp]);

(The first can be written: wordarray[temp] = &argv[1][temp]; which
might make more sense to some readers.)
}
}
for (temp=0; temp < numleft; temp++) {
printf("wordarray[temp] = %s\n",wordarray[temp]);
}
free(wordarray);
return 0;
}

The other possible "correction" would have been to allocate storage to
allow wordarray to point to a 2-byte string containing a copy of
argv[1] followed by a null byte.
 
K

Keith Thompson

I need to take a command line parameter and store it as an array.
i.e. program parameter1 should be stored like this:
wordarray[0]=p
wordarray[1]=a
wordarray[2]=r
wordarray[3]=a
wordarray[4]=m
wordarray[5]=e
etc
or if I do program para1 para2 it should be stored like this:
wordarray[0]=para1
wordarray[1]=para2

Your problem statement is unclear.  Your first example shows a single
word being split up into individual characters; your second shows each
word being stored in its entirety.  Is that really what you want?
Does the behavior change with the number of arguments?

You *might* be trying to do something like this:

    If there's one argument
        Store each character of the argument in an array element
    If there's more than one argument
        Store each argument in an array element

but I can't think of any good reason to do that.  (And what if there
are no arguments?)

There will always at least 1 argument.

What if I run your program with no arguments? Shouldn't you check for
that possibility, and at least print an error message?
From the responses so far I
must not have explained my problem clearly. I need a variable length
array whose elements point to either a string or a character. I
didn't post the entire program as it would 1573 lines of code.

A technical point: the phrase "variable length array" has a specific
meaning, and it's not what you appear to be trying to create. You're
creating a dynamically allocated array (using malloc).

You say the elements "point to either a string or a character".
Here is a working version of the code:
"working"??

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int numleft, temp;
char **wordarray; /* array to store words */

numleft=argc-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");

A minor point: This should probably go to stderr, not stdout.
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1];
}

You had 2 or more command-line arguments. Now each element of
wordarray points to one of those strings.
}
else {
numleft=(int)strlen(argv[1]);

Lose the cast.
printf("numleft = %d\n",numleft);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}

Some of the above code is identical in both branches of your if/else.
Consider hoisting it outside the if, so there's only one copy of the
code.
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1][temp];

There's your problem. wordarray[temp] is a char*; argv[temp+1][temp]
is a char. Also, I think you want argv[1][temp]; otherwise you're
stepping through nonexistent arguments.
printf("argv[temp+1]temp = %c\n",argv[temp+1][temp]);
}
}
for (temp=0; temp < numleft; temp++) {
printf("wordarray[temp] = %s\n",wordarray[temp]);
}
free(wordarray);
return 0;
}
[...]

So you really do want to split a single argument into individual
characters, and leave multiple arguments as whole words. Ok, but that
still seems like a very odd thing to want to do.

A "pointer to a string" is really just a pointer to the first
character of the string, so a char* can either point to a string or to
an individual character. Rather than

wordarray[temp] = argv[temp+1][temp];

you could just write:

wordarray[temp] = &argv[temp+1][temp];

But then you have to remember that the char* pointers point to
individual characters, not to strings; for example, you can't pass the
pointers to strlen() or use them with a "%s" printf format.

Or, as Ben suggested, you could allocate a 2-byte array for each
character and copy the character followed by a '\0' terminator --
which means you'll have to remember to free() each one. And of course
you'll have to remember *not* to free() each element if there are
multiple arguments. Unless you change the multiple-argument code so
it allocates new space for each argument as well.
 
J

jkelt46

The types here are wrong, as the compiler is telling you.  One
interpretation of what you want is to replace these two lines with:

      wordarray[temp] = argv[1] + temp;
      printf("argv[temp+1]temp = %c\n",argv[1][temp]);

(The first can be written: wordarray[temp] = &argv[1][temp]; which
might make more sense to some readers.)

Thank you for the help. I have tried your code and I nolonger get a
compiler error. However the output is:
../help dog
numleft = 3
wordarray[temp] = dog
wordarray[temp] = og
wordarray[temp] = g

instead of
../help dog
numleft = 3
wordarray[temp] = d
wordarray[temp] = o
wordarray[temp] = g

Latest code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int numleft, temp;
char **wordarray; /* array to store words */

numleft=argc-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1];
}
}
else {
numleft=(int)strlen(argv[1]);
printf("numleft = %d\n",numleft);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[1] +temp;
}
}
for (temp=0; temp < numleft; temp++) {
printf("wordarray[temp] = %s\n",wordarray[temp]);
}
free(wordarray);
return 0;
}
 
B

Barry Schwarz

There will always at least 1 argument. From the responses so far I
must not have explained my problem clearly. I need a variable length
array whose elements point to either a string or a character. I
didn't post the entire program as it would 1573 lines of code.

An array of pointer to char will allow you to do this, if you treat it
properly.
Here is a working version of the code:

Not hardly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
int numleft, temp;
char **wordarray; /* array to store words */

numleft=argc-1;
if (numleft > 1) {
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1];
}
}
else {
numleft=(int)strlen(argv[1]);

What purpose do you think the cast serves?
printf("numleft = %d\n",numleft);
wordarray=malloc(numleft * sizeof(*wordarray));
if (wordarray == NULL) {
printf("can't allocate memory for wordarray\n");
exit(EXIT_FAILURE);
}
for (temp=0; temp < numleft; temp++) {
wordarray[temp] = argv[temp+1][temp];

How can you claim your code works when this is a constraint violation
requiring a diagnostic? Furthermore, at this point you know that argc
is 2 so as soon as temp is incremented to 1 you attempt to access the
non-existent argv[2][1].

What would work in this case is
wordarray[temp] = &argv[1][temp];
printf("argv[temp+1]temp = %c\n",argv[temp+1][temp]);

More undefined behavior.
}
}
for (temp=0; temp < numleft; temp++) {
printf("wordarray[temp] = %s\n",wordarray[temp]);

You invoke this code regardless of the value of argc. When argc is 2
it will not do anything reasonable. Depending on what wordarray[temp]
points to, it may invoke undefined behavior.
}
free(wordarray);
return 0;
}

gcc -Wall help.c -o help
help.c: In function ‘main’:
help.c:29: warning: assignment makes pointer from integer without a
cast

This is not an example of code working.
./help dog cat bird
wordarray[temp] = dog
wordarray[temp] = cat
wordarray[temp] = bird

./help dog
numleft = 3
argv[temp+1]temp = d
Segmentation fault

This is also not an example of code working.
 
B

Ben Bacarisse

Keith Thompson said:
Or, as Ben suggested, you could allocate a 2-byte array for each
character and copy the character followed by a '\0' terminator --
which means you'll have to remember to free() each one. And of course
you'll have to remember *not* to free() each element if there are
multiple arguments. Unless you change the multiple-argument code so
it allocates new space for each argument as well.

Just to clarify... I had hoped to leave it vague enough to allow one
allocation:

char *buffer = malloc(2 * strlen(argv[1]));

wordarray then points to buffer[2*i] which is set to argv[1] and
buffer[2*i + 1] is set to zero.

Because char * requires no special alignment, it is possible to get
away with only one allocation in *both* cases by putting the space for
the buffer after the pointers. There is then nothing to remember: you
have one thing to free in all cases:

size_t npointers = argc == 2 ? strlen(argv[1]) : argc - 1;
size_t bsize = argc == 2 ? 2 * npointers : 0;
char **wordarray = malloc(npointers * sizeof *wordarray + bsize);
...
free(wordarray);

(All this needs to be protected from the case when argc == 0. When
argc == 1 the ... code should be written to do nothing.)
 
B

Ben Bacarisse

The types here are wrong, as the compiler is telling you.  One
interpretation of what you want is to replace these two lines with:

      wordarray[temp] = argv[1] + temp;
      printf("argv[temp+1]temp = %c\n",argv[1][temp]);

(The first can be written: wordarray[temp] = &argv[1][temp]; which
might make more sense to some readers.)

Thank you for the help. I have tried your code and I nolonger get a
compiler error. However the output is:
./help dog
numleft = 3
wordarray[temp] = dog
wordarray[temp] = og
wordarray[temp] = g

instead of
./help dog
numleft = 3
wordarray[temp] = d
wordarray[temp] = o
wordarray[temp] = g

Yes, I know. I'd write this:

int main(int argc, char *argv[])
{
if (argc > 0) {
size_t i;
size_t npointers = argc == 2 ? strlen(argv[1]) : argc - 1;
size_t bsize = argc == 2 ? 2 * npointers : 0;
char **wordarray = malloc(npointers * sizeof *wordarray + bsize);

if (wordarray == NULL) {
fprintf(stderr, "Can't allocate memory for word array.\n");
return EXIT_FAILURE;
}

if (argc > 2)
for (i = 0; i < npointers; i++) {
wordarray = argv[i+1];
}
else if (argc == 2) {
char *buffer = (void *)&wordarray[npointers];
for (i = 0; i < npointers; i++) {
wordarray = &buffer[2 * i];
wordarray[0] = argv[1];
wordarray[1] = 0;
}
}

for (i = 0; i < npointers; i++) {
printf("wordarray[%d] = %s\n", (int)i, wordarray);
}
free(wordarray);
}
return EXIT_SUCCESS;
}

I did not post this first because I thought you needed to say what you
really want. Is this coursework? I'm having trouble seeing why you'd
want to process the arguments in this way.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top