int main()
{
void fun(char *);
char str[] = "some text";
fun(str);
return 0;
}
void fun(char* ps){
while(*ps){
cout << *ps++;}
cout << endl;
}
So this is one of the examples in a c++ text book by Robert Lafore which illustrates the example of string passed in a function.
While explaining the example it is mentioned that the array address str is passed to the function. This address is constant, but since it is passed by value here. and a copy of it is created in fun().
I am not able to understand this statement as it is c style string which is a constant pointer which behaves similar to the array. The name itself should be the address and and we pass address to the function.
My questions are:
How it is being passed by value if the name itself is address?
Why it is the copy being created when we are passing the pointer argument to the fun()?
I got really confused here.
I might be wrong even in my basics, so an explanation would be great here.
As you probably know, every parameter (variable) of function is stored on the stack (special memory dedicated to local variables) somewhere and acts as new variable.
So your function:
void fun(char* ps)
{
...
}
has variable 'ps' of type 'pointer to char' which exists within the scope of 'fun' function and nowhere else.
So when you use it from other function (such as your main), then you'll have two variables containg pointer to the "some text" string. Namely 'str' inside main and 'ps' inside 'fun' function. The 'ps' is that copy mentioned in the book.
Also you have to distinguish between term 'address' and 'variable'. Address is WHAT is stored and variable is WHERE it is stored.
So for example, this code:
char my_character = 'x';
char *a = &my_character;
char *b = &my_character;
char *c = &my_character;
are three DIFFERENT variables (the one having type char*) but they ALL contain same value - address of my_character variable.
Let us take a look at what is happening in each of the statements in your program.
Statement 1
Here we consider the statement void fun(char *);.
This statement is a declaration for a function named fun that has one parameter of type char* and return type of void. This means that this function takes a pointer to char(char*) as argument by value and returns nothing(void).
Statement 2
Here we consider the statement char str[] = "some text";
This statement defines an array of char named str. That is, the type of str is char [10].
Statement 3
Here we consider the statement fun(str);
This statement calls the function named fun by passing str as an argument. There are 2 important things to note here:
Since the argument is passed by value, str decays to a pointer to char due to type decay. This means, char [10] decays to char *. Remember from statement 1 that the function fun expects a char* as argument and this is exactly what we are supplying/providing it. In particular, we are providing it a pointer to the first character of the array which is nothing but char*.
By value means the argument is copied. But note that in our case the argument is nothing but a char*(from point 1 above due to decay).This is why it is written that:
but since it is passed by value here. and a copy of it is created in fun().
Related
I have one function which have argument as char** I need to pass an array value in the same argument how could I pass that?
int fun(char** val)
{
std::cout<<"val:"<<*val<<"\n";
}
int main()
{
char ch[20];
strlcpy(ch, "test", sizeof(ch));
fun(&ch[0]) // here how can I pass the char array getting build issue
}
I think it is best to figure out, what the intent of the function fun is on the basis of the signature, i.e. the type of the parameter:
fun takes a pointer to a pointer to a single character or to the beginning of a bunch of characters. In the first place this means fun wants to have a "reference" to a pointer. This usually means func wants to modify this pointer and pass this modification back to the caller. It seams val is in fact an out parameter containing a pointer. If this is you actual intend, go with this function signature! In this case you would call fun this way:
char *c = NULL;
fun(&c);
// c is set by fun to a certain value
If you simply want to print out the characters it is way easier and much more obvious for a reader of your code to change the signature of fun to
int fun(char *val) { /* ... */ }
This says fun takes a pointer to a single character or a bunch of characters. It will get this pointer by value, any modification to the pointer itself won't be visibly outside of fun. In this case you'll call fun by
char c[] = "Hello World!";
fun(c);
Now, why did you get a build issue: The type of &ch[0] is char *, i.e. a pointer to some characters. But your fun expected char **, i.e. a pointer to a pointer to some characters. That's clearly an issue. And it contradicts the intend expressed by the function signature too: fun wants to have a "reference" to a pointer in order to modify this referenced pointer.
Edit: So, it sounds like you're stuck with a weird API and need to pass an character array into a function expecting a char ** parameter. In this case the other answers provide the correct, albeit still questionable solution:
char c[] = "Hello World";
char *ptr = &c[0];
fun(&ptr);
The ptr points to the first character of c. The variable ptr has itself an address, namely &ptr, which has type char **. So &ptr is the needed "reference" to a pointer to a bunch of characters you can pass to fun.
But be aware of the fact, that fun is free to change the value of ptr, i.e. the address ptr itself points to. It might be possible that, returning from the call to fun, the value of ptr is something completely different, pointing to an address you didn't expect. Heck, it might be even possible that you're expected to call free(ptr) at the end even though you started with an address in ptr to some static memory you shall never call free() to. To know these details you have to read the detailed specifications of the function fun.
ch is a char[] array. &ch[0] is dereferencing the array to access the 1st element, yielding a char, and then is taking the address of that char, yielding a char*. But the function wants a char** instead. So save that char* to a variable and pass the address of that variable to the function, eg:
int main()
{
char ch[20];
strlcpy(ch, "test", sizeof(ch));
char *ptr = ch; // same as: ptr = &ch[0]
fun(&ptr);
}
Assume a function with one parameter of const char* type. When I use a string when calling that function, nothing goes wrong! I would expect that you could only input characters included in the ASCII, for example c or dec 68, but it seem otherwise. Take a look at the code below...
void InitFunction(const char* initString)
{
std::cout << initString;
}
int main()
{
InitFunction("Hello!");
}
When you run the code, no problem, warnings, or errors appear. I did some more testing on this as you can see from the following...
void InitFunction(char initString)
{
std::cout << initString;
}
int main()
{
InitFunction("Hello!"); // compiler error on this line
}
This compiles with an error since Hello! cannot be converted into char. I tried another test, but instead used const char as the function parameter type. The code still compiles with an error. But when I add * to the function parameter type, then everything compiles fine! It appears to me that the const is also necessary.
To my understanding of pointers, the function is asking for a pointer, and the pointer is identified as being a character. But this raises three problems for me.
First, Hello! is not in the form of a pointer. I would expect at least to have to use the reference operator (&).
Second, Hello! is not a char type.
And third, why do we need to include the const?
Am I missing something here? Do pointers and characters work in ways that I don't know?
"Hello!" is a const char array of characters. Arrays are treated like a pointer, they decay to a pointer when used in a function call as an argument. The C++ standard specifies this in order to be compatible with the way that the C language standard specifies arrays are to be treated.
By the way this array decay to a pointer happens with other cases where an array is being used where a pointer or the address operator could be used such as an assignment statement. See also Arrays are Pointers?
So "Hello!" will be put into the argument list of InitFunction() as a pointer which points to where the compiler has stored the array of characters with the terminating zero character added. When the compiler generates the code for the function call, the pointer to the array of characters used as an argument to the function is const char *, a pointer to a char which is const and should not be changed.
When you have the function prototype as InitFunction(const char *), the compiler is fine with a function call such as InitFunction("Hello!");. What you are doing is providing a const char * that points to "Hello!".
However if you remove the const then since "Hello!" is a const the compiler complains. The compiler complains because a const variable is being used in a function call whose argument list is non-const indicating that the function may change what the pointer is pointing to. Since "Hello!" is not supposed to be changed, since it is const, the compiler issues an error.
If you remove the asterisk, change const char * to const char, then since "Hello!" is a char array which the compiler then decays into a pointer to the first element of the array, the compiler complains as you are trying to use a pointer for an argument that is not a pointer. In this alternative the problem is the actual data type, char versus char * is the problem.
The following lines of code would also be acceptable:
const char *p = "Hello!"; // create a pointer to an series of characters
char x1[] = "Hello!"; // create an array of char and initialize it.
char *p2 = x1; // create a pointer to char array and initialize it.
char *p3 = x1 + 2; // create a pointer to char array and initialize it with address of x1[2].
InitFunction (p); // p is a const char *
InitFunction (x1); // x1 decays to a char *
InitFunction (p2); // p2 is a char *
InitFunction (p3); // p3 is a char *
InitFunction (x1 + 3); // called with address of x1[3].
Note also C++ has an actual character string type, string, that results in a dynamic character text string whose underlying physical memory layout normally includes a pointer to an array of characters. The C style array of characters that is labeled a string is not the same thing as the C++ string type.
the function is asking for a pointer
Correct.
and the pointer is identified as being a character
No, a pointer is a not a character. A pointer is a pointer. This pointer points to one or more characters, i.e. an array of characters. And that's exactly what your string literal is.
First, Hello! is not in the form of a pointer.
Yes, it is. The string literal "Hello!" has type const char[7] and this decays to a pointer.
I would expect at lest to have to use the reference operator (&).
That's the address-of operator. You don't always need it to get a pointer. Example: this.
Second, Hello! is not a char type.
No, but each constituent character is.
And third, why do we need to include the const?
Because the string literal "Hello!" has type const char[7]. Dropping the const would violate const-correctness and is therefore not permitted.
This throws an error since Hello! cannot be converted into char.
That's right. A char is one byte. The string "Hello!" is not one byte. It is a string.
A C-string is typically/conventionally/usually provided in const char* form.
You should read the chapter in your book about this subject as it's a fundamental of the language. It has nothing to do with ASCII (text encodings are irrelevant to storing a sequence of bytes).
#include <iostream>
#include <cstring>
using namespace std;
class student {
int roll_no;
char name[56];
public:
void setdata(int roll_no_in, const char* name_in) {
roll_no = roll_no_in;
strcpy(name, name_in);
}
void outdata() {
cout << "rollno is " << roll_no << endl << "name is " << name << endl;
}
};
int main() {
student s1;
s1.setdata(12, "robin");
s1.outdata();
return 0;
}
i have some doubts in this program
how can we store strings into pointer like above program storing the string robin into char *name_in since pointers are used only to store address.Can we store even strings?
why should i add const in the method function set data if i don't use
that then it shows me error. It is optional right?
why can't i use char name_in[34] in the place of char *name_in in the setdata method function?
C strings are arrays of char. When you pass an array as a function argument, it's converted to a pointer to the first element.
The const modifier indicates that the function will not modify the contents of name_in. Since string literals are constants, you need this to permit the function to be called with a literal argument.
You can. But since the function doesn't actually have a limit on the size of the string it will accept, that would be misleading. Declaring a parameter as an array with a length is treated just like declaring it as a pointer; the length you specify is ignored. Note: This is only true for the first dimension; when passing a multi-dimensional array, you can omit the first dimension's length, but need to specify all the other dimensions.
how can we store strings into pointer like above program storing the string johnson into char *name_in since pointers are used only to store address.
You're not storing it in name_in, you're storing it into name, which is an array. name_in is a pointer to the array passed to the function; the array is automatically converted to a pointer when passed to a function. (More generally, a pointer can point to the start of an array, and be used to access the array; C-style functions like strcpy do exactly that.)
In idiomatic C++, you'd use a class rather than this dangerous mucking about with pointers and arrays:
std::string name;
name = name_in;
why should i add const in the method function set data if i dont use that then it shows me error.
I assume you mean in const char * name_in. You're passing a pointer to a string literal, which is constant; and the language doesn't allow you to take a non-constant pointer to a constant object.
It is optional right?
Before C++11, it was optional; leaving it out was merely a very bad idea. Now it's mandatory.
why can't i use char name_in[34] in the place of char *name_in in the setdata method function
You can; as a function argument, both are equivalent. Again you'll need const to be able to pass a string literal or other constant string. It would be somewhat misleading though, implying that name_in is an array, of a particular size, when neither are guaranteed.
Again, this is C++, so std::string is almost certainly a better option than either.
*how can we store strings into pointer like above program storing the string johnson into char name_in since pointers are used only to store address.Can we store even strings?
You are actually storing pointer to the base address of the string. You can use this pointer to traverse whole string.
why should i add const in the method function set data if i dont use that then it shows me error
"Ravi" is a string literal which is stored in memory which is read only. So, if you try to pass this literal to function accepting char *, it would be the violation of the constraint compiler is trying to establish.
*why can't i use char name_in[34] in the place of char name_in in the setdata method function?
You are passing pointer to char to this function, so you have to use pointer to char to accept it. However, arrays , when passed to function as argument decays to a pointer.
Can I pass an array to printf directly:
char text[1024] = "text";
printf("%s", text);
Or should I explicitly cast it to a char pointer:
char text[1024] = "text";
printf("%s", (char*) text);
I'm asking because I thought maybe it copies the array elements directly into the va_list instead of putting just a pointer to the first element.
Yes, you can pass an array directly. Exactly, name of array represents address of the array which makes no difference with char *.
(char*)text and text hardly make any difference in this example! Base address of an array decays into a pointer when passed as a function argument.
In fact, even if text was not a char array, still it would hardly make any difference to printf because it is a variable argument function
int printf(const char *format, ...);
and all it cares is about the first argument. Logic might go wrong but printf doesn't care!
Short answer, yes, arrays in C _are_a pointer to their first element. (Edit: Longer answer, well, actually, arrays in C are identifiers or labels which are just names, but when used as part of an expression that doesn't preface them with & or sizeof they get converted into or otherwise evaluated as pointers).
Even longer answer: You see, functions can't really receive an array as an argument, but the compiler has to send them something, so it sends them a pointer. Thus the first sentence should probably start with "As far as functions like printf() are concerned..."
Some functions purport to take an array, but that's just an illusion. These two functions are the same.
func(char *a);
func(char a[]);
The C FAQ entry below goes into more detail about the subtle differences between arrays and pointers:
char a[] = "this";
char *b = "that";
a[0] generates completely different code than b[0] yet they are roughly equivalent in that the subscripting operator [] gives us the expected result.
Interestingly, the format specifier "%s\n" is also passed to printf() as a pointer.
http://www.lysator.liu.se/c/c-faq/c-2.html
Isn't an array/arrayname always a pointer to the first element in C?
Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be replaced by an expression of type "pointer to T" whose value is the address of the first element of the array.
When you write
printf("%s", text);
the expression text is replaced by a new expression of type char * whose value is &text[0], and this pointer value is what gets passed to printf. This means you don't have to cast the argument. It also means that you cannot pass an array expression as a function parameter and have the called function receive it as an array type. The conversion happens before the function is called.
names of pointers and arrays are exchangeable. (Besides the memory allocation)
When you have
char *a = "abcdef";
char b[5];
You could write
char z = a[2]; // 'c'
char x = *b;
char y = *(b+2);
But you can't do
b ++;
You may consider array b as char * const b as a unmodifyable pointer
I have a function that will pass a string and manipulate. in the function call i am passing the string as such like myfunc ("hello");
In the function definition i have
myfunc (char *array)
{
xxxx
};
The program is working fine, but it throws a warning "pointer targets in passing argument 1 of 'myfunc' differ in signedness".
How to rectify this problem?
Strings are actually arrays of constant characters. That is, the type of "hello" is const char[6].
What this means is you cannot modify it. However, due to a silly conversion in C++, the array (in string literal form) can be implicitly converted to a non-const pointer to the first element. This is misleading, and dangerous. (Indeed, a const-stripping implicit conversion doesn't exist anywhere else.)
You should make sure you have a modifiable buffer instead:
char buffer[] = "hello";
myfunc(buffer);
Make sure your definition for myfunc() function has char* as parameter. I think, it has unsigned char* as parameter. or somewhere else in your code, you are passing unsigned char* as argument to myfunc(char*). Look at the warning line in your code.
I think Prasoon is right. Your compiler is treating "string literals" as unsigned char. Just change your function to accept unsigned char ...or change the compiler setting which decides if a "string literal" is signed/unsigned.
what if you declare your function like myfunc (const char *array)