Static variables and pointers
Static variables and pointers
|
I have an array indexing version of the function reverse (s) that reverses the characters in the string s (skipping the \0 at the end) and puts a new \0 at the end of resulting string s.
Now I have to change it into a pointer version. This is what I get:
C code reverse (ps) char *ps; { static char *ps1 = ps, *ps2 = ps; //this is line 57 int c; if ((c = *ps1++) != '\0') reverse (*ps); if (c != '\0') *ps2++ = c; *ps2 = '\0'; }
Now, obviously this isn't right, and it returns the error:
AtoI, ItoA.c:57: error: initializer element is not constant
AtoI, ItoA.c:57: error: initializer element is not constant
The problem is that in the array version I used a static int i1 and i2, and used them as indexes of the string s.
Now I have to somehow initialize the two internal pointers to ps, so that I can reverse the string without changing where ps is pointing to, but I have to only do it once, not every time the function is called, otherwise the recursion won't work properly.
Is there a workaround for this, or do I have to make a completely different function?
...and that's the bottom line because Mate de Vita said so.
|
|
|
|
≡
|
2011 Mar 17 at 22:08 UTC
|
|
|
|
You don't need to worry about changing ps because it won't affect where it is pointing in the outer calls to the function.
Go ahead and mess with it all you want.
Do you have to use recursion for this? This is a really bad use of recursion. It adds a lot of confusion and complexity for nothing.
If you must use recursion, you should just pass along the end pointer or the length. It's not really "recursion" if you have global variables. This would make a lot more sense:
C code void reverse( char *start, char *end );
Then if you want to make the initial invocation simpler, just make another function with only the start and have it call reverse( start, start+strlen(start) )
And is there a reason you are using the ancient 1978 style argument lists?
|
|
|
|
≡
|
2011 Mar 17 at 23:12 UTC
|
|
|
|
superjer said: You don't need to worry about changing ps because it won't affect where it is pointing in the outer calls to the function.
Go ahead and mess with it all you want.
Oh OK, that's good then.
superjer said: Do you have to use recursion for this? This is a really bad use of recursion. It adds a lot of confusion and complexity for nothing.
Well, there was an Exercise that required that I make a version of reverse (s) using recursion (this was before I even got to pointers). I didn't really know how else I would go about doing that.
Now I just took that same routine and replaced the strings and string indexes with pointers.
I guess I could just go ahead and write a new function from scratch.
EDIT: Done, here it is:
C code reverse (ps) char *ps; { char temp; char *end = ps + strlen (ps) - 1; while (ps < end){ temp = *ps; *ps++ = *end; *end-- = temp; } }
superjer said: And is there a reason you are using the ancient 1978 style argument lists?
Not quite sure what you mean by that (unless you mean that I declare the variables separately, not in the argument list), but anyway, I'm learning C with K&R's book, which is about that age.
P.S. I'm quite bad at programming terminology, so you have to excuse me if I use some terms improperly. What's the difference between a routine, a subroutine, a procedure, a method, and a function?
...and that's the bottom line because Mate de Vita said so.
|
|
|
|
≡
|
2011 Mar 18 at 16:17 UTC
— Ed. 2011 Mar 18 at 17:09 UTC
|
|
|
|
Mate de Vita said: Not quite sure what you mean by that (unless you mean that I declare the variables separately, not in the argument list), but anyway, I'm learning C with K&R's book, which is about that age.
That's what I meant. Not really a problem, just weird. You know there's a 2nd edition of K&R, right?
Mate de Vita said: P.S. I'm quite bad at programming terminology, so you have to excuse me if I use some terms improperly. What's the difference between a routine, a subroutine, a procedure, a method, and a function?
Nothing.
At least not in C. C only has "functions" but they do just as well as procedures, subroutines, etc.
In some languages they might mean different things but not by much.
"Method" usually refers to a member function of a class in OOP. But it's still just a function, really.
|
|
|
|
≡
|
2011 Mar 18 at 19:02 UTC
|
|
|
|
Mate de Vita said: EDIT: Done, here it is:
C code reverse (ps) char *ps; { char temp; char *end = ps + strlen (ps) - 1; while (ps < end){ temp = *ps; *ps++ = *end; *end-- = temp; } }
See, that's a good solution. You can turn any loop into recursion but it's not generally helpful.
I guess it's an OK exercise. But I think it would be better with a problem where recursion makes things a lot easier, not harder.
|
|
|
|
≡
|
2011 Mar 18 at 19:10 UTC
— Ed. 2011 Mar 18 at 19:11 UTC
|
|
|
|
superjer said: You know there's a 2nd edition of K&R, right?
I saw on wikipedia, yes. But I only have this one and can't be assed to search for an online version.
New problem, I have the function itoa (n, s), which turns an integer into its decimal string representation (so the number 123 becomes a char array with the elements '1', '2', '3', '\0').
C code itoa (n, ps) char *ps; int n; { int i = 0, tf = 0, sign; char *start = ps; if (n == -n && n != 0) n++, tf++; //! if ((sign = n) < 0) n = -n; do { *ps++ = n % 10 + '0'; } while ((n /= 10) > 0); if (sign < 0) *ps++ = '-'; if (tf) *start = *start + 1; //! *ps = '\0'; reverse (start); }
Notice the lines marked with exclamation marks, those are the ones I added myself (the rest was copied from the book). The Exercise reads:
Quote: Exercise 3-3. In a 2's complement number representation, our version of itoa does not handle the largest negative number, that is, the value of n equal to -(2^(wordsize-1)). Explain why not. Modify it to print that value correctly, regardless of the machine it runs on.
The problem here is the process by which the computer calculates the negative number: by calculating its binary complement and incrementing it by one. In the case of -(2^(wordsize-1)), this becomes C(10000...)+1, which is 01111...+1, which in turn is again 10000..., so you get the same number.
My solution works in this case but it's rather clumsy. If the number in question ended in a 9, I would have to make *start = '0' and *(start+1)++, and so on until the end of the string. Now obviously, in this particular case this isn't a problem, since 2^n, where n is an integer, can never end with a 9.
Still, is there a better, more general solution to this problem? For example, what happens if I have to implement this into a different function where the above is possible?
Btw, can *start = *start + 1 be written instead as (*start)++ ?
...and that's the bottom line because Mate de Vita said so.
|
|
|
|
≡
|
2011 Mar 18 at 22:05 UTC
— Ed. 2011 Mar 18 at 22:14 UTC
|
|
|
|
Mate de Vita said: Btw, can *start = *start + 1 be written instead as (*start)++ ?
Yes.
Mate de Vita said: Still, is there a better, more general solution to this problem? For example, what happens if I have to implement this into a different function where the above is possible?
I would skip forcing n to be positive, and just do the loop regardless of the sign, using absolute value:
C code itoa (n, ps) char *ps; int n; { int i = 0, sign = n; //! char *start = ps; do { *ps++ = abs(n % 10) + '0'; //! } while (n /= 10); //! if (sign < 0) *ps++ = '-'; *ps = '\0'; reverse (start); }
In C the sign of the result of % with negative number(s) is implementation-defined, though, so this isn't perfect. On some systems, -13 % 10 equals 7, which would give the wrong answer. I guess to be really safe, you have to do this:
C code itoa (n, ps) char *ps; int n; { int i = 0, sign = n, digit; //! char *start = ps; do { digit = n % 10; //! if (sign < 0 && digit > 0) digit -= 10; //! *ps++ = abs (digit) + '0'; //! } while (n /= 10); if (sign < 0) *ps++ = '-'; *ps = '\0'; reverse (start); }
Here's my test code BTW:
C code #include <limits.h> #include <stdio.h> ... main() { int i; char s[100]; itoa ( INT_MIN , s ); printf ("%s\n",s); itoa ( INT_MIN+1, s ); printf ("%s\n",s); for (i = -12; i <= 12; i++) { itoa ( i, s ); printf ("%s\n",s); } itoa ( INT_MAX-1, s ); printf ("%s\n",s); itoa ( INT_MAX , s ); printf ("%s\n",s); }
|
|
|
|
≡
|
2011 Mar 19 at 02:01 UTC
— Ed. 2011 Mar 19 at 02:07 UTC
|
|
|
Page [1]
|
|