LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-06-2011, 09:45 AM   #1
nindzadza
LQ Newbie
 
Registered: Jan 2011
Posts: 4

Rep: Reputation: 1
Unable to dynamically create an array of params for execv in C


Hello everyone and thank you for looking at my little problem. I haven't programmed in C for a while, so I am trying to remember certain aspects of syntax. I have a program that will fork and exec other programs. Those programs will be specified on the command line as follows:

./main "prog1 arg arg ..." "prog2 arg arg ..."

Here is the main snippet:

int countChar(char* s, char c)
{
int cnt = 0;
int len = strlen(s);
for(int i = 0; i < len; i++)
{
if(s[i] == c) cnt++;
}
return cnt;
}

char** stringToArray(char* s, int *size)
{
char **array = (char**)calloc(countChar(s, ' '), sizeof(char*));
char * pch = strtok(s, " ");
int i = 0;
while(pch != NULL)
{
int len = strlen(pch);
array[i] = (char*)calloc(len, sizeof(char));
strcpy(array[i++], pch);
pch = strtok(NULL, " ");
}
*size = i;
return array;
}

char* proc1 = (char*)malloc(strlen(argv[1]));
char* proc2 = (char*)malloc(strlen(argv[2]));
strcpy(proc1, argv[1]);
strcpy(proc2, argv[2]);

int length = 0;
char ** arr = stringToArray(proc1, &length);

for(int i = 0; i < length; i++)
{
printf("%d: %s\n", i, arr[i]);
}

char* const params[] = &arr[1];
execv(arr[0], arr[0], params, 0);

The highlighted line is the problem. I get this error:

dualstarter.cpp:58: error: initializer fails to determine size of ‘params’.

Right now I am thinking of creating an array with the specified size and simply copying the required string into it, but it just seems like there is an easier way. I appreciate any feedback you have, thank you.

Last edited by nindzadza; 01-06-2011 at 09:46 AM.
 
Old 01-06-2011, 09:57 AM   #2
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by nindzadza View Post
...
char* const params[] = &arr[1];
execv(arr[0], arr[0], params, 0);

The highlighted line is the problem. I get this error:

dualstarter.cpp:58: error: initializer fails to determine size of ‘params’.

Right now I am thinking of creating an array with the specified size and simply copying the required string into it, but it just seems like there is an easier way. I appreciate any feedback you have, thank you.
Based on which statement of C99 standard ( http://www.open-std.org/JTC1/SC22/wg...docs/n1124.pdf ) you wrote the problematic initializer ?
 
0 members found this post helpful.
Old 01-06-2011, 11:15 AM   #3
nindzadza
LQ Newbie
 
Registered: Jan 2011
Posts: 4

Original Poster
Rep: Reputation: 1
I guess it feels great to wave the C99 standard in my face and imply: "You are stupid, didn't you read this whole document to not make such stupid mistakes?" If that was not your intent, I apologize, but it very much comes off like that. Nonetheless, having searched through the document the closest thing I could find was on page 117:

EXAMPLE 3 The following declarations demonstrate the compatibility rules for variably modified types.
extern int n;
extern int m;
void fcompat(void)
{
int a[n][6][m];
int (*p)[4][n+1];
int c[n][n][6][m];
int (*r)[n][n][n+1];
p = a; // invalid: not compatible because 4 != 6
r = c; // compatible, but defined behavior only if
// n == 6 and m == n+1
}

Except in my case I was trying to shift the pointer from the existing array by one value down and declare a new array starting from the shifted value:

int a[3];
int b[2] = &a[1];

As I already know this does not work, but my question is - is there a way for me to do what I want?
 
Old 01-06-2011, 11:20 AM   #4
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by nindzadza View Post
I guess it feels great to wave the C99 standard in my face and imply: "You are stupid, didn't you read this whole document to not make such stupid mistakes?" If that was not your intent, I apologize, but it very much comes off like that. Nonetheless, having searched through the document the closest thing I could find was on page 117:

EXAMPLE 3 The following declarations demonstrate the compatibility rules for variably modified types.
extern int n;
extern int m;
void fcompat(void)
{
int a[n][6][m];
int (*p)[4][n+1];
int c[n][n][6][m];
int (*r)[n][n][n+1];
p = a; // invalid: not compatible because 4 != 6
r = c; // compatible, but defined behavior only if
// n == 6 and m == n+1
}

Except in my case I was trying to shift the pointer from the existing array by one value down and declare a new array starting from the shifted value:

int a[3];
int b[2] = &a[1];

As I already know this does not work, but my question is - is there a way for me to do what I want?
What does the standard say about initialization ? The example you posted is not related to initialization, your problem is.
 
0 members found this post helpful.
Old 01-06-2011, 11:27 AM   #5
dugan
LQ Guru
 
Registered: Nov 2003
Location: Canada
Distribution: distro hopper
Posts: 11,223

Rep: Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320
Sergei, seriously... just cite the chapter and verse. (e.g. 5.2.2).

Last edited by dugan; 01-06-2011 at 11:29 AM.
 
Old 01-06-2011, 11:41 AM   #6
nindzadza
LQ Newbie
 
Registered: Jan 2011
Posts: 4

Original Poster
Rep: Reputation: 1
Page 127:
22. If an array of unknown size is initialized, its size is determined by the largest indexed
element with an explicit initializer. At the end of its initializer list, the array no longer
has incomplete type.

I guess for the compiler to initialize the array it needs to be defined with an explicit brace notation... Hmm, I'll have to figure out how to initialize through the brace notation I guess.
 
Old 01-06-2011, 11:56 AM   #7
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by nindzadza View Post
Page 127:
22. If an array of unknown size is initialized, its size is determined by the largest indexed
element with an explicit initializer. At the end of its initializer list, the array no longer
has incomplete type.

I guess for the compiler to initialize the array it needs to be defined with an explicit brace notation... Hmm, I'll have to figure out how to initialize through the brace notation I guess.
So now it's high time to talk about stupidity.

Quote:
You are stupid, didn't you read this whole document
- yes, to write such a thing is stupid. Specifically, it is stupid because:
  1. the compiler tells something about initialization;
  2. the above item in bold is common for words like "initial", "initializer", "initialization", etc;
  3. the standard is a PDF file, hence electronic search does work;
  4. the item (substring) to be looked for is, of course, "initial";
  5. in the light of all the above it is utterly stupid to assume the whole document should be read.
 
0 members found this post helpful.
Old 01-06-2011, 12:30 PM   #8
nindzadza
LQ Newbie
 
Registered: Jan 2011
Posts: 4

Original Poster
Rep: Reputation: 1
I get what you are trying to do. "Don't give the fish to the man, but teach him to fish." I did search through the document, and I did find the section about initialization. The part about "whole document" was an exaggeration. My problem is that the size of the array can not be determined by the compiler during the initialization. The closest thing I could find I already posted. Just FYI, searching for "initial" brings up 368 references, if the document didn't contain the contents section plowing through that would be a little too much. Also, just some constructive criticism:

In my understanding the point of the website is to help people with Linux problems, in my case a programming problem in Linux environment. I do not expect you to solve my problem and give me the solution on the silver platter. Simply explain what I am doing wrong in a snippet of the code that does not work, and maybe tell me how I can fix it. Your approach is to show me the language standard, which is equivalent to showing the construction worker a blueprint of the tool he is having trouble with and tell him the answer is there. Of course the answer is SOMEWHERE there, but thats the reason this website exists - to find people who already know the part of the blueprint you are looking for and explain it to you, so you don't have to read the unnecessary information. A funny thing, you still didn't say if I am on the wrong or the right track and I get the gist you don't know yourself. You saw the post, didn't know the answer, but your ego simply couldn't resist, so you sent me on the search adventure. In your last post you come off as a douchbebag, but please pay attention to the words, you COME OFF as one, not that I am calling you that.
 
1 members found this post helpful.
Old 01-06-2011, 12:32 PM   #9
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
These are wrong:
Code:
char* proc1 = (char*)malloc(strlen(argv[1]));
char* proc2 = (char*)malloc(strlen(argv[2]));
Should be:
Code:
char* proc1 = (char*)malloc(strlen(argv[1]) + 1);   /* extra character for null terminator */
char* proc2 = (char*)malloc(strlen(argv[2]) + 1);
Of course, the code above is not necessary; if all you require is a copy of a string within an allocated chunk of memory, then use strdup().
Code:
char* proc1 = strdup(argv[1]);   /* allocates memory and copies the string */
char* proc2 = strdup(argv[2]);
Do something similar within stringToArray() as you are strtok()-ing the string that is passed in.
Code:
...
char * pch = strtok(s, " ");
int i = 0;

while(pch != NULL)
{
    array[i++] = strdup(pch);

    pch = strtok(NULL, " ");
}
...
 
1 members found this post helpful.
Old 01-06-2011, 12:51 PM   #10
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by nindzadza View Post
I have a program that will fork and exec other programs. Those programs will be specified on the command line as follows:
Code:
./main "prog1 arg arg ..." "prog2 arg arg ..."
Don't do that. See how standard utilities handle this, e.g. find .. -exec.

POSIX.2 specifies -- to be the end of options, so you might use e.g. --- as the command separator:
Code:
./main prog1 arg arg... --- prog2 arg arg... --- prog3 arg arg [---]
This way you do not need to parse any strings, just split the argv[] into multiple arrays at "---" strings (allowing for a trailing "---"); no string operations needed except for strcmp(), just pointer array stuff. The shell will then handle the argument parsing/splitting, handling quotes and all that mess.

Since this works exactly like other programs with respect to argument parsing, there would be no surprises for users. Consider, for example, how in your calling convention you would handle spaces in parameters.

You'll find the code is much, much simpler this way, too.

If you really need your calling convention for some reason, you could then use a simple wrapper script:
Code:
#!/bin/bash
ARGS=()
while [ $# -gt 0 ]; do
ARGS=("${ARGS[@]}" $1 ---)
shift 1
done
exec path-to-real-main "${ARGS[@]}"
This would always use Bash parameter splitting rules, thus minimal surprise for users.
Nominal Animal

Last edited by Nominal Animal; 03-21-2011 at 01:45 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Bash - read array dynamically Garcia16 Programming 16 09-26-2010 01:50 AM
local dynamically allocated array in fortran otoomet Programming 5 10-21-2009 08:28 AM
Dynamically set array length in Fortran77? halfpower Programming 2 12-15-2005 08:03 AM
In C, using qsort for dynamically allocated array ntmsz Programming 7 08-23-2005 10:33 AM
dynamically expanding an array in c++ a1ghagh05t Programming 4 03-07-2004 09:00 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:41 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration