By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,985 Members | 1,863 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,985 IT Pros & Developers. It's quick & easy.

Is ((char **) &var_name); a cast to char array giving existing pointer to var_name?

P: 13
I am currently reading/learning c. I often like to look at code while I read, - to see more practical use then often are feasible in educational books.

I am looking at some code from wget.

Code extracted from wget.
Expand|Select|Wrap|Line Numbers
  1. /* file: mswindows.c */
  2. void
  3. windows_main (char **exec_name)
  4. {
  5.   char *p;
  6.  
  7.   /* Remove .EXE from filename if it has one.  */
  8.   *exec_name = xstrdup (*exec_name);
  9.   p = strrchr (*exec_name, '.');
  10.   if (p)
  11.     *p = '\0';
  12. }
  13.  
Expand|Select|Wrap|Line Numbers
  1. /* file: main.c */
  2.  
  3. const char *exec_name;
  4.  
  5. int
  6. main (int argc, char **argv)
  7. {
  8.   /* Construct the name of the executable, without the directory part.  */
  9.   exec_name = strrchr (argv[0], PATH_SEPARATOR);
  10.   if (!exec_name)
  11.     exec_name = argv[0];
  12.   else
  13.     ++exec_name;
  14.  
  15. #ifdef WINDOWS
  16.   /* Drop extension (typically .EXE) from executable filename. */
  17.   windows_main ((char **) &exec_name);
  18. #endif
  19.  
  20. ...
  21.  
  22.  
My question goes to what is happening around the call on windows_main from within main, file main.c.

As i understand it it goes something like this:
main:
  1. An unchangeable pointer of type char is made by const char *exec_name
  2. ((char **) &exec_name) - this confuses me. Is it making a new char array with address pointing to address of pointer exec_name, or is it some sort of cast?
  3. What about the fact that exec_name is a const? Wouldn't this prohibit change of exec_name?
windows_main:
  1. windows_main takes a char array as argument.
  2. since exec_name is a const, a editable copy is made by xstrdup, but can this point to same location as the const?
  3. the pointer p is given the address of last dot ('.') in exec_name by strrchr
  4. if p has index higher then 0, the value at that index is given '\0', thus terminating the string exec_name at that position.

... this is mighty probable confusing to read... :/


Code for xstrdup:

Expand|Select|Wrap|Line Numbers
  1.  
  2. void
  3. xalloc_die (void)
  4. {
  5.   error (exit_failure, 0, "%s", _("memory exhausted"));
  6.  
  7.   /* The `noreturn' cannot be given to error, since it may return if
  8.      its first argument is 0.  To help compilers understand the
  9.      xalloc_die does not return, call abort.  Also, the abort is a
  10.      safety feature if exit_failure is 0 (which shouldn't happen).  */
  11.   abort ();
  12. }
  13.  
  14. /* Allocate N bytes of memory dynamically, with error checking.  */
  15.  
  16. void *
  17. xmalloc (size_t n)
  18. {
  19.   void *p = malloc (n);
  20.   if (!p && n != 0)
  21.     xalloc_die ();
  22.   return p;
  23. }
  24.  
  25. /* Clone an object P of size S, with error checking.  There's no need
  26.    for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
  27.    need for an arithmetic overflow check.  */
  28.  
  29. void *
  30. xmemdup (void const *p, size_t s)
  31. {
  32.   return memcpy (xmalloc (s), p, s);
  33. }
  34.  
  35. /* Clone STRING.  */
  36.  
  37. char *
  38. xstrdup (char const *string)
  39. {
  40.   return xmemdup (string, strlen (string) + 1);
  41. }
  42.  
  43.  
Sep 19 '10 #1

✓ answered by newb16

Yes, cast is done on the address - it's the address that is passed to the function, and it is cast. But the only constness is changed is the constness of 'char', not pointers. Was - pointer to pointer to const char, become - pointer to pointer to char. In both cases, pointers can be changed, but the char itself can't.
Expand|Select|Wrap|Line Numbers
  1. const char **x;
  2. x=0; //ok
  3. *x=0; //ok
  4. **x=0; //error;

Share this Question
Share on Google+
4 Replies


100+
P: 687
>An unchangeable pointer of type char is made by const char *exec_name

No. Unchangeable pointer would be "char *const exec_name", and it could't be assigned by exec_name = strrchr (argv[0], PATH_SEPARATOR); Here it is a pointer to unchangeable string. So in order to pass it to windows_main (that actually changes the string) one need to remove constness by bruteforce C way.
I't not clear to me why is it not declared as "char *exec_name;"

This may work without cast - returning a new string from xmemdup by assigning to char* const temporary variable.

Expand|Select|Wrap|Line Numbers
  1. void windows_main(const char ** exec_name)
  2. {
  3.   char* mutable_string = (char*)xmemdup(*exec_name);
  4.   // alter new string
  5.   mutable_string[1]=0;
  6.   // now return it and promise that it's immutable
  7.   char* const foo(mutable_string);
  8.   *exec_name = foo;
  9. }
  10.  ...
  11.  windows_main (&exec_name);
  12.  
Sep 19 '10 #2

P: 13
Thank you for reply.

Then unchangeable pointer is out of the way :)
In other words a const character pointer are defined, and as soon as it is initialized by exec_name = strrchr (argv[0], PATH_SEPARATOR); the result is a constant character array (null terminated string)

So the "((char **) &exec_name);" is a cast then?

My test:
Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. const char *k;
  5.  
  6. void
  7. test (char **x)
  8. {
  9.     printf("*x = %p, &x = %p, x = %p, str = %s, **x = %c\n", *x, &x, x, *x, **x);
  10.  
  11.     **x = 'F';
  12. }
  13.  
  14. int
  15. main (int argc, char **argv)
  16. {
  17.  
  18.     k = argv[0];
  19.     printf("*k = %c, &k = %p, k = %p, str = %s\n", *k, &k, k, k);
  20.     test((char **) &k);
  21.     printf("*k = %c, &k = %p, k = %p, str = %s\n", *k, &k, k, k);
  22.     return 0;
  23. }
  24.  
  25.  
Result in

Expand|Select|Wrap|Line Numbers
  1. >tool
  2. *k = t, &k = 004050DC, k = 003E3EA9, str = tool
  3. *x = 003E3EA9, &x = 0022FF30, x = 004050DC, str = tool, **x = t
  4. *k = F, &k = 004050DC, k = 003E3EA9, str = Fool
  5.  
So somehow k becomes editable by casting it. But I am still not sure how I would express what is happening. What I find weird is that the cast is done on an address.
Sep 19 '10 #3

100+
P: 687
Yes, cast is done on the address - it's the address that is passed to the function, and it is cast. But the only constness is changed is the constness of 'char', not pointers. Was - pointer to pointer to const char, become - pointer to pointer to char. In both cases, pointers can be changed, but the char itself can't.
Expand|Select|Wrap|Line Numbers
  1. const char **x;
  2. x=0; //ok
  3. *x=0; //ok
  4. **x=0; //error;
Sep 20 '10 #4

P: 13
Thank you :)
Sep 20 '10 #5

Post your reply

Sign in to post your reply or Sign up for a free account.