To my knowledge the standard strcmp function looks something like this:
int strcmp(const char* string1, const char* string2)
{
while(*pString1++ == *pString2++)
{
if(*pString1 == 0) return 0;
}
return *pString1 - pString2;
}
My question is that wouldn't this increment the pointers passed into strcmp? In the following example it seems like it would trash the pointers and cause invalid stuff to happen.
const char* string1 = "blah";
const char* string2 = "blah";
const char* string3 = "blah";
if(strcmp(string1, string2) {doSomething();}
// Won't this make string1 = "" because it incremented the pointer to the end?
else if (strcmp(string1, string3) {doSomethingElse();}
Sorry I'm just confused because it seems like if I pass a pointer into strcmp, I shouldn't expect that pointer to suddenly hold an empty string. It seems like strcmp should take const char* const. Am I totally misunderstanding something?
Your misunderstanding is this: Arguments are passed by value (copy), but you seem to think they are passed by reference.
You could get your expected behaviour by declaring the parameters to strcmp as references, like this:
int strcmp(const char*& string1, const char*& string2)
No, the pointers string1 and string2 are local to the function (passed by value). Any changes made to them are not visible to the caller.
The pointer itself is passed by value, so although it's a pointer to something, changing it does change the local declaration only.
To be able to modify the pointer itself from the inner scope of the function you would need to have a pointer to pointer to char.
The pointers are passed by value, strcmp is using copies of the ones you send in, so the original ones aren't touched.
First, the classical obfuscated implementation of strcmp is even
simpler:
int
strcmp(char const* s1, char const* s2)
{
while ( *s1 ++ == *s2 ++ )
;
return *s1 - *s2;
}
(I would hope that no one would actually write code like this in
practice.)
As for your actual question: C++ (and C, since this is really a C
question) pass arguments by value, so any pointer that strcmp gets is
a copy; it can't possibly modify any of the pointers in the calling
code. All making the parameters char const* const would mean is that
strcmp couldn't modify its local copies of the pointers.
C++ passed parameters to functions "by value". Consider this code:
void f(int i) { i = 7; }
...
int j = 0;
f(j);
assert(j == 0);
The variable j is unrelated to the variable i. Indeed, i local to the function f. It is initialized with a copy of of j. Changes to i are never communicated to j.
Now consider this code:
void f(char *i) { i = i + 1; }
...
char *j = "Hello";
f(j);
assert(*j == 'H');
Similarly, i is initialized with a copy of j. Changes to i are never communicated back to j.
Note: One can force parameters to be initialized "by reference" thusly:
void f(int& i) { i = 7; }
...
int j = 3;
f(j);
assert(j==7);
In this case, rather than being initialized with a copy of j, i is bound to a j. But this only applies if you have & in the declaration.
Try this, your will find that they are totally different pointer.
What cause you misunderstand is that they point to the same area
#include <iostream>
using namespace std;
int strcmp2(char const *s1, char const *s2)
{
cout << "In strcmp" << endl;
cout << &s1 << " " << &s2 << endl;
cout << endl;
}
int main()
{
char a[100];
char b[100];
cout << "In main function" << endl;
cout << &a << " " << &b << endl;
cout << endl;
strcmp2(a, b);
}
Related
I have what is hopefully a trivial question that someone can explain to me in simpler terms than what I have already come across. While working through
A Tour of C++ (Second Edition)
I've been trying a few examples.
I'm currently trying to modify a pointer to a string literal in a separate function (I thought it would be easy.....).
using namespace std;
void test(char *ptr)
{
ptr = "test";
}
int main()
{
char *p = "abc";
test(p);
cout << p << "\n";
return 0;
}
When using g++ to compile, I get a
Warning: ISO C++ forbids converting a string constant to char*
Apparently g++ is auto-converting *p to a const? Surely I'm missing something basic, but my previous SO and google searches have gotten me no closer to the answer. Thank you for your responses!
EDIT:
Both great examples below. Thank you everyone for your responses, very helpful!
Apparently g++ is auto-converting *p to a const?
Quite the opposite. The string "abc" will be in your binary, and that is supposed to be readonly for your program. Therefore, that string should only be read, and the value you get when assigning the string literal in this situation is of type const char*. You get the error because you're assigning it to a non-const char*. Try this instead:
const char *p = "abc";
Also, you'll have to change the function, too:
void test(const char *ptr)
{
ptr = "test";
}
It's still going to print abc, however. That's because you're only modifying a copy of the value that you're passing. But C++ lets you pass a reference instead, which you can do like this:
void test(const char *&ptr)
{
ptr = "test";
}
Now that's a reference to a pointer pointing to a const char... whew! Both the "abc" and "test" will be in the program's binary when it is compiled. When the program is run, the address of "abc" is assigned to char *p, and then the function to change it to have the address of "test" instead is called. The & tells it to work with the actual char *p and not just a copy of it that gets lost when the function finishes.
There are two things that can be const; the pointer (char * const), or the object (const char *).
The string literal is const, that's what the compiler is complaining about. You should use
const char *p = "abc";
The function would still not modify the pointer p from main() though, because it is passed by value to the function.
This should modify the pointer:
using namespace std;
const char * str2 = "test";
void test(const char *& ptr)
{
ptr = str2;
}
int main()
{
const char *p = "abc";
test(p);
cout << p << "\n";
return 0;
}
live demo
How is it possible that the value of *p and the value of DIM are different but the have the same address in memory?
const int DIM=9;
const int *p = &DIM;
* (int *) p = 18; //like const_cast
cout<< &DIM <<" "<< p << '\n';
cout << DIM << " " << *p << '\n';
You're changing the value of a const variable, which is undefined behavior. Literally anything could happen when you do this, including your program crashing, your computer exploding, ...
If a variable is supposed to change, don't make it const. The compiler is free to optimise away accesses to const variables, so even if you found a successful way to change the value in memory, your code might not even be accessing the original memory location.
It is a compiler optimization. Given that DIM is a constant, the compiler could have substituted its known value.
The code below does what you meant to do... as mentioned in other posts, if you mean to change the value of an variable, do not define it as const
#include <stdio.h>
int main()
{
int d= 9;
int *p_d=&d;
*p_d=18;
printf("d=%d\np_d=%d\n",d,*p_d);
return 0;
}
This code prints
d=18
p_d=18
I've posted a few pointer-related questions recently. I've tried to unite the confusion I'm suffering in this one post, so apologies if it looks familiar. The question is - why does funky() output the string whereas funkier() outputs the address? My logic tells me that the latter is what I would expect. Or is this just the way std::cout deals with things?
I notice that printf behaves the same way.
#include <iostream>
using namespace std;
void funky(const char* a);
void funkier(char* a[]);
int main() {
const char* y = "message";
funky(y);
char* z[3];
z[0] = "one";
z[1] = "two";
z[2] = "three";
funkier(z);
cin.get();
return 0;
}
void funky(const char* a) {
cout << a << endl; // prints the string.
}
void funkier(char* a[]) {
cout << a << endl; // prints the address.
}
The operator<< for std::ostream is overloaded for many different types of the right operand.
If the second operand is a const char* it is interpreted as a NUL-terminated string and printed.
If the second operand is a const void* it is printed as an address.
There are many other overloads, but these are not relevant here.
The funky() call uses the first overload.
But the funkier argument is actually a char**, which is neither of the above. But it is convertible to const void*, not to const char*, so the second overload is used.
Beware of printf()! That is a C function and it does not detect the type of the arguments. It expects you to pass the right %s or %p or whatever for each of the arguments. If you use the wrong letter, or pass the wrong argument type, you will probably get Undefined Behaviour.
char *x = "a";
printf("%s", x); //prints x as string
printf("%p", x); //prints x as pointer
printf("%d", x); //Undefined Behaviour!!!
printf("%d", (int)x); //prints the pointer value as an integer, if it fits
I am trying to pass a char & value to a char * argument in a function, but it's not working as shown below:
#include <iostream>
using namespace std;
void change_sugar(const short& sugars, char* LOC);
int main()
{
static int caga = 0;
const short* mysweets;
char& lala;
change_sugar(mysweets, lala);
}
void change_sugar(const short& sugars, char** LOC[])
{
if (sugars == 3000)
LOC[1] = 5;
cout << "Sugar is not nCaga, nor caga" << " ___ !#S ";
cerr << "nCaga failed!";
}
Error output:
error: 'lala' declared as reference but not initialized
I am trying to pass a reference to a pointer of the same type. Is this correct?
Bear with me, I am new to C++, and I think I read the tutorial on pointers and references correctly.
EXTRA: I tried this with a different compiler, Turbo 16, I think, and it threw like ten other errors, so I don't know if it's a compiler problem or not.
In C++ a reference must always be valid (and not "dangling"), so you have to initalize it when creating it.
I am not sure what you wanted to do with your lala, but a proper usage of a reference variable is like so:
char a;
char & b = a; // has to be initialized here
Now you can use b wherever a variable of type char is meant to be used. However, your function wants char * as its second parameter.
Thus, after initializing the reference, you could still use its address to make it fit: &lala.
Also your definition and declaration is mismatched.
There are lots of things wrong with your code.
A reference and a pointer are not the same thing in the C++ language, although they are implemented the same way in the compiled machine code. You cannot pass a reference where a pointer is expected, and vice versa. You are trying to pass a short* where a short& is expected, and a char& where a char* is expected.
A reference can never be uninitialized (hense the compiler error), but a pointer can be uninitialized.
The parameters in your change_sugar() declaration do not match the parameters in the definition. In C++, they must match.
It is very unclear what change_sugar() is actually trying to do. Clearly, you want to alter the char that is passed in, but char is only 1 byte in size and you are trying to alter memory past the 1-byte boundary of the data being altered.
Try this instead:
#include <iostream>
using namespace std;
void change_sugar(const short& sugars, char* LOC);
int main()
{
short mysweets = 3000;
char lala = 0;
change_sugar(mysweets, &lala);
}
void change_sugar(const short& sugars, char* LOC)
{
if ((LOC) && (sugars == 3000))
*LOC = 5;
cout << "Sugar is not nCaga, nor caga" << " ___ !#S ";
cerr << "nCaga failed!";
}
Or this:
#include <iostream>
using namespace std;
void change_sugar(const short& sugars, char& LOC);
int main()
{
short mysweets = 3000;
char lala = 0;
change_sugar(mysweets, lala);
}
void change_sugar(const short& sugars, char& LOC)
{
if (sugars == 3000)
LOC = 5;
cout << "Sugar is not nCaga, nor caga" << " ___ !#S ";
cerr << "nCaga failed!";
}
There's a very simple paradigm for passing variables to methods wanting pointers:
void clear(char *p) { *p = '\0'; }
char c = 'a';
clear(&c); // after this call c == '\0'
Are you actually looking for something more advanced here?
Reference variables:
char &r = c;
Are actually pretty complicated. (And would still be passed with &r)
There are a lot of things that bothers me with the code so I'll go through some them.
1: Your prototype does not match.
Change
void change_sugar(const short& sugars, char** LOC[])
to
void change_sugar(const short& sugars, char* LOC)
or the other way around depending on what you actually want to do.
2. Your pointer is not initialized.
const short* mysweets is not initialized. Allocate some memory for it.
const short* mysweets = malloc(sizeof(short));
then
*mysweets = 3000;
3. lala is not a pointer.
If you want to pass the address of lala to your function, change_sugar, initialize it as so
char* lala = malloc(sizeof(char));
and pass it as
change_sugar(mysweets, lala);
If you don't want it to be a pointer but still want to pass by reference, declare it as so
char lala;
and pass it as
change_sugar(mysweets, &lala);
Finally:
Your code is very confusing to read and to figure out what you actually want to do. I suggest to step back and think about what you want to achieve and redesign your code.
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
void f(char **x)
{
(*x)++;
**x = 'a';
}
int main()
{
char str[]="hello";
f(&str);
cout << str << endl;
return 0;
}
Please tell me why this program is giving compilation Error.I am using the g++ compiler
Error :temp1.cpp:16:8: error: cannot convert ‘char (*)[6]’ to ‘char**’ for
argument ‘1’ to ‘void f(char**)’
Arrays can be implicitly converted to pointers, but that doesn't mean that the implicit "pointer equivalent" already exists.
You are hoping that f(&str); will implicitly create both a pointer to str and a pointer to that pointer.
This small (working) change illustrates this point:
int main()
{
char str[]="hello";
char *pstr = str; // Now the pointer extists...
f(&pstr); // ...and can have an address
cout << str << endl;
return 0;
}
You are passing pointer of constant char to the function but in function you are taking it as pointer of pointers. That is the problem. I commented out below where the problem lies.
[Off topic but N. B. : Arrays and pointers are different concept.]
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
void f(char **x) //**x is pointer of pointer
{
(*x)++;
**x = 'a';
}
int main()
{
char str[]="hello";
f(&str); //You are passing pointer of constant char.
cout << str << endl;
return 0;
}
You're going to run into a serious problem with your function f since &str and &str[0] both evaluate to the same value ... as other posters have pointed out, these operations point to different types, but the actual pointer r-value will be the same. Thus in f when you attempt to double-dereference the char** pointer x, you're going to get a segfault even if you attempted something like a cast to massage the type differences and allow compilation to happen with errors. This is because you are never getting a pointer-to-pointer ... the fact that &str and &str[0] evaluate to the same pointer value means that a double-dereference acually attempts to use the char value in str[0] as a pointer value, which won't work.
Your problem is that you're treating arrays as pointers, when they're not. Arrays decay into pointers, and in this case, it doesn't. What you're passing in is a char (*)[6] when it expects a char **. Those are obviously not the same.
Change your parameter to char (*x)[6] (or use a template with a size parameter):
template <std::size_t N>
void f(char (*x)[N])
Once inside, you try to increment what x is pointing to. You can't increment an array, so use an actual pointer instead:
char *p = *x;
p++;
*p = 'a';
All put together, (sample)
template <std::size_t N>
void f(char(*x)[N])
{
if (N < 2) //so we don't run out of bounds
return;
char *p = *x;
p++;
*p = 'a';
}