implicit convertion from constant character array to character array - c++

in the snippet code bellow when I pass a literal string to the function it gives me a warning ISO C++ forbids converting a string constant to 'char*but when I assign a character array to this literal the warning will be gone. I know that the type of string literals in C++ is constant character array but the type of ch variable is just char.(not constant char)
#include <iostream>
using namespace std;
void func(char s[])
{
cout << s;
}
int main() {
char ch[] = "what";
func(ch);
func("what"); //gives warning
return 0;
}
and I have one question more. when I add const to input parameter type of func function there is no warning in this situation too even though I pass a character array to the function not const character array.I thought it should cause a warning for fucn(ch) call because ch is a character array not constant character array.
#include <iostream>
using namespace std;
void func(const char s[])
{
cout << s;
}
int main() {
char ch[] = "what";
func(ch);
func("what");
return 0;
}

const is not about matching exactly, but about what the function is doing to the parameter.
If you define a function with a const parameter, the function promises to not change the passed variable. Therefore, you can call it with constant strings as well as (changable) non-constant variables. The compiler will warn you if you try to modify the value inside the function (because you promised you wouldn't).
If you define a function with a non-constant parameter, it can change the parameter. Therefore, the compiler warns you if you pass a constant string, as that would lead to undefined behavior / crashes.

Related

Please explain char* return type in C++ [duplicate]

This question already has answers here:
cout << with char* argument prints string, not pointer value
(6 answers)
Closed 2 years ago.
I have written a simple C++ code, and its working fine. But I don't know how it is working. I am just replacing "l" with "r" using myfun().
The return type of myfun() is char*. If I am returning &(str[0]), that is, only the address of the first element of the array, then why is it printing the complete string "herloworld"? Please explain what return &(str[0]); is doing.
#include <iostream>
using namespace std;
char* myfun(char str[])
{
str[2] = 'r';
return &(str[0]);
}
int main()
{
char str[] = "helloworld";
char* word;
word = myfun(str);
cout << word;
}
The operator << is overloaded for the type char * such a way that it expects that the used pointer of the type char * points to the first character of a string.
So the operator outputs all characters of the passed string until the zero character '\0' is encountered.
Also pay attention to that arrays used in expressions with rare exceptions are converted to pointers to their first elements.
So this call
word = myfun(str);
is equivalent to
word = myfun( &str[0]);
On the other hand, a function parameter having an array type is implicitly adjusted to pointer to the element type.
So this function declaration
char* myfun(char str[]);
is equivalent to the following declaration
char* myfun(char *str);
The both declarations declare the same one function.
And within the function instead of this return statement
return &(str[0]);
you could write
return str;
Correspondingly in main you could write
cout << myfun(str);
without declaring and using the intermediate pointer word.

"Cannot convert char* to char(*)[95]" error

I have code for using an array to create an ASCII table. I am having trouble compiling the code due to errors:
cannot convert 'char*' to char(*)[95] for argument '1' to void buildTable(char (8)[95], int)
and
cannot convert std::ofstream to char(*)[95] for argument '1' to 'void printTable(char(8)[95], int)
#include <iomanip>
#include <iostream>
#include <fstream>
int main () {
const int MAX_SIZE = 95;
char symbols[MAX_SIZE];
int values[MAX_SiZE], int values);
void buildTable (char [][MAX_SIZE], int values);
void printTable (char [][MAX_SIZE], int values);
void output(std::fstream, std::string, double);
std::string line;
std::ofstream outputFile;
outputFile.open("ascii.log");
if(outputFile.fail()) {
std::cout << "Error opening file. \n";
return 1;
}
else {
buildTable (symbols, values, MAX_SIZE);
printTable (outputFile, symbols, values, MAX_SIZE);
}
outputFile.close();
return 0;
}
The variable symbols is an array of char. It will decay to a pointer to its first element, &symbols[0], which will be of type char*.
The functions you declare takes its first parameter as a pointer to an array of char. A pointer to an array of char is very different from a pointer to char.
The solution is to make the function take the same data-type as you pass, i.e. a pointer to char, char*.
You also have multiple other problems. For example the functions you declare (buildTable and printTable) are currently declared to that this wrong argument as the first argument, and then int value as second argument. But that's not how you call those functions. You need to declare the functions with their actual arguments, and call them as declared.
On a related note: Since you program in C++ please don't use character arrays for strings, use std::string instead. It will save you a lot in the long run.

char pointers, char arrays, and strings in the context of a function call

What is the difference between the line that does not compile and the line that does compile?
The line that does not compile gives this warning: deprecated conversion from string constant to 'char*'
Also, I'm aware casting (char *) on the string being passed in to the function would solve the problem, but I would like to understand why that's even necessary when the 2nd line compiles just fine.
class Student {
public:
Student( char name[] ) {
}
}
int main() {
Student stud( "Kacy" ); //does not compile
char name[20] = "Kacy"; //compiles just fine
}
The char[] signature in the parameter is exactly the same as char*. In C++, it is illegal to convert a string constant char const* (the string "Kacy") to a char* because strings are immutable.
Your second example compiles because the name is an actual array. There is no change to char*.
As a solution, change your parameter to take a const string array:
Student(char const name[]);
which again is the same as
String(char const *name);
though you're better off using std::string:
#include <string>
class String
{
public:
String(std::string name);
};
C++ string literals have type "array of n const char", which decays into const char * in your use case. The implicit conversion to char * (that is, discarding the const) you're trying is deprecated, so there's a warning. Change the type in the constructor's signature or make an explicit const-cast.
From the C++ standard:
An ordinary string literal has type "array of n const char" and static storage duration
The string
"Kacy"
is not an array of characters when the compiler produces the code. Instead, it will stash the string "Kacy" somewhere in memory, and produce a pointer to that place. So what you get is a const char * pointing at the string "Kacy\0".
If you change your constructor to:
Student(const char *nmae)
you can use it both as:
Student stud("Kacy");
and as this:
char name[20] = "Kacy";
Student stud2(name);
Note here that the compiler will generate code to FILL the array name with the characters in "Kacy", which is different from just usinv "Kacy" as an argument to the Student constructor.

what does skip procedure do?

i am trying to determine what does this code?
#include <cstdlib>
#include <iostream>
#include<string.h>
using namespace std;
char *skip(char *p,int n)
{
for (;n>0;p++)
if (*p==0) n--;
return p;
}
int main(int argc, char *argv[])
{
char *p="dedamiwa";
int n=4;
cout<<skip(p,n)<<endl;
}
When I run it om dev c++,it wrotes
`basic_string::copy`
When i run it on ideone.com,it wrotes
prog.cpp: In function ‘int main(int, char**)’:
prog.cpp:15: warning: deprecated conversion from string constant to ‘char*’
prog.cpp:18: warning: ignoring return value of ‘int system(const char*)’, declared with attribute warn_unused_result
It searches for a certain number of \0 (n number of \0). It is undefined behaviour because it goes after the end of the string.
For the const part, string literals are const in c++. In c they aren't but still they mustn't be modified otherwise you get an undefined behavior (often a crash) (so even in c it's normally better to declare them as const and live happy)
The reason of the result of basic_string::copy is that in your (compiler/implementation specific, but quite common) compiled program there is an area where all the constant strings are saved "together". So if you go after the end of one, you go to the beginning of another. So someplace in your executable there is something like:
dedamiwa\0something\0somethingelse\0somethingelseelse\0basic_string::copy
It interpret the first parameter as a pointer to an array of character containing at least n null characters, and return a pointer after the n-th such null-character. Per se, there is no undefined behavior if you pass correct input to it.
Since you pass a simple null terminated string, it has undefined behavior, as there is only one such null-character in its input. It will access memory after the end of the string.
Concerning the compilation errors, in C++ a constant string is of type const char*, not char*, and you should check the return of the system function for error.
It skips n characters of the char array.
It interpret the first parameter as a pointer to an array of character
containing at least n null characters, and return a pointer after the
n-th such null-character. Per se, there is no undefined behavior if
you pass correct input to it.
Since you pass a simple null terminated string, it has undefined
behavior, as there is only one such null-character in its input. It
will access memory after the end of the string.
Concerning the compilation errors, in C++ a constant string is of type
const char*, not char*, and you should check the return of the system
function for error. by -- Sylvain Defresne
A version of the code with explicit braces is maybe a little bit
more readable for you:
using namespace std;
char *skip(char *p,int n){
for (;n>0;p++)
if (*p==0) {
n--;
}
return p;
}
To get rid of the error:
int main(int argc, char *argv[])
{
// cast the string which is of the type const char* to the
// type of the defined variable(char*) will remove your warning.
char *p= (char*) "dedamiwa";
int n=4;
cout<<skip(p,n)<<endl;
}
The skip procedure is asking for a segfault.
Basically, it increments p until the next '\0' is found, and repeats that n times.
In the best case, nothing will be printed because '\0...' is an empty string for std::cout(std::ostream&, const char *).
In the worst case, there be nasal dragons, to quote comp.lang.c.

How does a function detect string pointer vs string literal argument?

I have encountered a function, such that it can differentiate between being called as
foo("bar");
vs
const char *bob = "bar";
foo(bob);
Possibilities I have thought of are:
Address of string: both arguments sat in .rdata section of the image. If I do both calls in the same program, both calls receive the same string address.
RTTI: no idea how RTTI can be used to detect such differences.
The only working example I could conjure up is:
void foo(char *msg)
{
printf("string literal");
}
void foo(const char *&msg)
{
printf("string pointer");
}
foo("bar"); // "string literal"
const char *soap = "bar";
foo(soap); // "string pointer"
I do not have access to the function's code, and the declarations in the header file only revealed one function declaration.
Here's another way to distinguish between a string literal and a pointer, based on the fact that string literals have array type, not pointer type:
#include <iostream>
void foo(char *msg)
{
std::cout << "non-const char*\n";
}
void foo(const char *&msg) // & needed, else this is preferred to the
// template function for a string literal
{
std::cout << "const char*\n";
}
template <int N>
void foo(const char (&msg)[N])
{
std::cout << "const char array reference ["<< N << "]\n";
}
int main() {
foo("bar"); // const char array reference [4]
}
But note that all of them (including your original function) can be "fooled" by passing something that isn't a string literal:
const char *soap = 0;
foo(soap);
char *b = 0;
foo(b);
const char a[4] = {};
foo(a);
There is no type in C++ which is unique to string literals. So, you can use the type to tell the difference between an array and a pointer, but not to tell the difference between a string literal and another array. RTTI is no use, because RTTI exists only for classes with at least one virtual member function. Anything else is implementation-dependent: there is no guarantee in the standard that string literals will occupy any particular region of memory, or that the same string literal used twice in a program (or even in a compilation unit) will have the same address. In terms of storage location, anything that an implementation can do with string literals, it is permitted also to do with my array a.
The function foo() in theory could use a macro to determine if the argument was a literal or not.
#define foo(X) (*#X == '"'
? foo_string_literal(X)
: foo_not_string_literal(X))
And what happens if you call it as:
const char bob[] = "bar";
foo(bob);
It's probably using some sort of distinction like that to make the determination.
EDIT: If there's only one function declaration in the header I can't conceive of any portable way the library could make that distinction.