0

I'm populating a C program to multiply 2 input vectors. Here is the code:

/**
 * Function name: parseArguments
 * Description:
 *    Determine what options or arguments user used
 *    Command-line options:
 *   [-h]    : Show help information
 *   [-n] num: Determine number of threads
 *   file1   : Choose first file
 *   file2   : Choose second file
 * Return value:
 *    0: If parsing successful
 *    exit: If error
 **/
static int parseArguments(int argc, char **argv, int* nthreads, char* file1, char* file2)
{
  int opt;
  int help=0;
  extern int optind;
  extern char * optarg;    // (global variable) command-line options

  while ((opt = getopt(argc, argv, "hn:")) != EOF)
  {
    switch (opt) {
      //Parse option -h, -n
      case 'n':
        *nthreads = atoi(optarg);
        break;
    case 'h':
        Usage();
        exit(1);
        break;
      default:
        fprintf(stderr, "Try 'mulvector -h' for more information\n");
        exit(1);
    }


    // parse file1 & file2 arguments
// THIS IS WHAT I'M ASKING
        if (optind < argc)
    {
        file1 = &argv[optind];
        optind++;
    }
    if (optind < argc)
        file2 = &argv[optind];
  }

  return 0;
}

The problem is that, after i called this function (in the main() function) and then exit this function (continue the main() function), the 2 variables file1 & file2 still keep their old values before executing the parseArguments function. I'm trying to fix this but i get no result ...

Hope you guys can help, thanks so much in advanced !

NOTE: The type of file1 and file2 are char file1[1024] so i can't use char** as the arguments for the parseArguments function !

sonlexqt
  • 6,011
  • 5
  • 42
  • 58

5 Answers5

2

C passes arguments by value. The modifications that you make to file1 and file2 are therefore only modifications to the local copies of the pointers that exist inside the function. The caller does not see those changes.

You probably want to either:

  1. Copy text to the buffers that file1 and file2 refer to, or
  2. Pass the addresses of file1 and file2 to the function and modify the values seen by the caller.

Option 1 looks like this:

static int parseArguments(..., char* file1, char* file2)
{
    ....
    strcpy(file1, argv[optind]);
    ....
    strcpy(file2, argv[optind]);
    ....
}

Of course, this is asking for buffer overrun. So you would also be wise to pass the length of the buffer to allow the code to avoid that overrun, for example by using strncpy or strncat. There is a good discussion of the issue here: Why should you use strncpy instead of strcpy?

Option 2 looks like this:

static int parseArguments(..., char** file1, char** file2)
{
    ....
    *file1 = &argv[optind];
    ....
    *file2 = &argv[optind];
    ....
}
Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • thanks ! can you tell me how do i fix this error ? i want file1 and file2 to have the new parsed values ! – sonlexqt May 29 '14 at 09:00
  • Thanks, but i have forget to note that: The type of file1 and file2 are forced to `char file1[1024]` in main() function so i can't use char** as the arguments for the parseArguments function ! – sonlexqt May 29 '14 at 09:07
  • In that case you want option 1. – David Heffernan May 29 '14 at 09:10
1
file1 = &argv[optind];

If you want to modify a pointer object, you have to pass to the function a pointer to a pointer and not just the pointer object value.

That is:

char **file1, char **file2

instead of

char* file1, char* file2
ouah
  • 142,963
  • 15
  • 272
  • 331
  • Thanks, but i have forget to note that: The type of file1 and file2 are forced to `char file1[1024]` in main() function so i can't use char** as the arguments for the parseArguments function ! – sonlexqt May 29 '14 at 09:06
  • @rainman_TS7 in that case you don't want to modify a pointer! And remember that you cannot assign to an array. If you want to copy a string use a string copy function like `strncpy`. – ouah May 29 '14 at 09:09
0

C is pass-by-value, even for pointers. If you want to change a pointer, you need to pass in a pointer to it and then dereference the pointer to get to the variable behind it.

That means a double pointer to your function:

static int parseArguments (int      argc,
                           char   **argv,
                           int     *nthreads,
                           char   **pFile1,
                           char   **pFile2)

and calling it with the addresses of those pointers:

char *somePtr, *otherPtr;
int rc = parseArguments (..., &somePtr, &otherPtr);

It also means dereferencing within the function itself, such as:

*pFile1 = &argv[optind];

It would actually be quite easy it would be for ISO to fix this problem that people keep having with C having to emulate pass-by-reference.

They could simply add a special marker for variables in function prototypes to indicate that they're pass-by-reference and, therefore, access to them would be indirect in the function.

Whether this actually ever happens, it's hard to say.


As to your comment:

NOTE: The type of file1 and file2 are char file1[1024] so I can't use char** as the arguments for the parseArguments function!

If you want to pass in a buffer address that can't be modified, then you have to shift memory into that buffer (and ignore my comments above), such as with:

strcpy (file1, argv[optind]);

although you may want to either check the length beforehand to prevent buffer overflow, or use a safer bounds-checking memory copying function.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
0

Because you change addresses of pointers, unstead of values.

You have to ways:

  1. Get variables by link (char*& file1, char*& file2).
  2. Get them by pointer (char** file1, char** file2), but you shoul call your function like parseArguments(..., &charPointer1, &charPointer2)
Genovich
  • 155
  • 2
  • 7
0

If file1 and file2 point to valid memory, copy the contents of the memory where argc's elements point to, to where file1and file2points to, but assigningargc`'s elements' addresses.

To do so replace the assignment

file1 = &argv[optind];

by a copy operation

strcpy(file1, argv[optind]);

However doing so is risky as inside parseArgument() it isn't know how much memory hab been assigned to file and file2.

To get around this pass in to parseArguments also those sizes like this:

static int parseArguments(int argc, char **argv, int* nthreads, 
  char* file1, size_t size1, 
  char* file2, size_t size2)
{
  ...
  memset(file1, 0, size1);
  strncpy(file1, argv[optind], size1 - 1);
alk
  • 69,737
  • 10
  • 105
  • 255