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.
Related
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.
I am getting an error while copying one string to another string using pointers.
#include<iostream>
#include<string>
using namespace std;
void String_copy(char* scr,char* des)
{
while(*scr!='\0')
{
*des= *scr;
scr++;
des++;
}
}
int main()
{
char *str1, *str2;
str1="bharath";
str2="ygftygyfrgtg";
String_copy(str1,str2);
cout<<str1<<endl;
cout<<str2<<endl;
system("pause");
return 0;
}
In below code you have undefined behaviour:
char *str1, *str2;
str1="bharath";
str2="ygftygyfrgtg";
you should assign string literals only to const* char, this also means you should not modify str and str2
you can fix above with:
char str1[] = "bharath";
char str2[] = "ygftygyfrgtg";
but you must also fix String_copy - so that it checks bounds of arrays being modified, ie. add additional parameter with max length of des, also dont forget to add '\0` at the end.
First of all ISO C++ forbids converting string constants to char* pointers.
Try something like this instead to define str1 and str2:
char str1[]="bharath";
char str2[]="ygftygyfrgtg";
Your second problem is the String_copy function, where you just check one of the strings for the terminal \0 character. Also you should add a \0 to the des string (in case it was initially longer):
Something like this will work:
void String_copy(char* scr,char* des){
while(*scr!='\0' && *des!='\0')*des++=*scr++;
*des=0;
}
Note that you can copy maximally up to the length of your shorter string, since you did not allocate more memory anywhere.
Also if it is possible you should use std::string
The two strings are different lengths but you only check for a zero terminator in one of them. Either use strings of equal length or check for the zero terminator in both (and decide what to do with the excess characters).
The problem is that "bharath" is not of type char*.
Its actually a type char const* but the language (for comapability with C) allows auto conversion between the two. If you turn on your warnings (and treat them as errors) this will not even be allowed to compiler:
> g++ -std=c++11 -Wall -Wextra -Werror sc.cpp
sc.cpp:36:10: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
str1="bharath";
Now (that you have fixed this) you are suffering from the issue that the destination string could be shorter than src. Which will result in the same problem (writing to memory you dont own).
this code throw me an Access violation error
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string a;
cin >> a;
printf("%s",a.at(1));
return 0;
}
I wrote this line because this function gave me problem with a larger program and i want to figure out what the problem really is...
thanks !
The immediate problem is that "%s" requires a pointer to a C-style string as its corresponding argument. a.at(1) is a single character, not a pointer, so you have undefined behaviour when it's misinterpreted as a pointer. You want "%c" to print a character.
The more general problem is the use of non-typesafe C functions. In C++, you could use a typesafe output stream:
cout << a.at(1);
std::string at returns a char type. Using the %s format specifier for a char type will give you undefined behaviour. Boom!
Two things:
1) Check the size of the string before accessing elements using at: at(1) is accessing the second character of the string as the indexing is zero based.
2) Use the correct format specifier in printf: printf("%c", a.at(1))
at() doesn't return a string, it returns a character. %s is trying to interpret that character as a (very invalid) pointer.
Try:
printf("%c", a.at(1));
(assuming a is at least two characters long).
The printf function expect a char pointer and you give a char. The char value gets interpreted as an address and it is wrong.
If you only want to print a single char, use:
printf("%c", a.at(1))
provided your string is at least 2 characters long.
I've written the following program to match regular expressions in C++
#include <regex.h>
#include <iostream>
using namespace std;
/*
* Match string against the extended regular expression in
* pattern, treating errors as no match.
*
* return true for match, false for no match
*/
bool match(const char *string, char *pattern)
{
int status; regex_t re;
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0)
return false;
/* report error */
status = regexec(&re, string, (size_t) 0, NULL, 0);
regfree(&re);
if (status != 0) {
return false; /* report error */
}
return true;
}
int main()
{
string str = "def fadi 100";
bool matchExp = match(str.c_str(), "^[Dd][Ee][Ff][' '\t]+[A-z]+([,])?[''\t]+[0-9]+$");
cout << (matchExp == true ? "Match": "No match") << endl;
}
The program works fine just as expected, but when I compile the code using gcc with the -Wall -Werror arguments (Linux environment), I get a very annoying warning message saying the following:
main.cpp: In function ‘int main()’:
main.cpp:33:90: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Is there a way to force the compiler to believe that str.c_str() is the same as char * str? if so, how?
No, there isn't. That conversion was deprecated in C++03 and is illegal in C++11; don't do it.
Deprecation of that conversion comes from the fact that string literals are read-only, hence const; accessing them using a pointer to non-const char could possibly lead to modifying const objects, hence invoking undefined behavior. The warning isn't annoying; it is meant to save you from possibly crashing your application - or worse.
Also, you are wrong in reading the warning message; it isn't about c_str(), it is about passing string literal as char *.
The only way to really fix your code is to change second parameter of your match to be const char *, not char *, and copy the passed string to a new, buffer, internal to that function (why not in main()? Because with internal buffer, you have less boilerplate on the caller's side).
I'd also like to suggest totally different solution, since the question is tagged "C++": Boost.Regex.
Is there a way to force the compiler to believe that str.c_str() is the same as char * str?
That's actually not the issue here - you are already passing str.c_str() as a const char*.
The issue is that the second parameter is (also) a string literal, but has type char*. Try changing the second parameter to const char*.
If that still raises errors (due to the regex.h functions not specifying the correct const-ness), you're going to have to do something like this in main() or match():
char pattern[] = "^[Dd][Ee]...etc";
bool matchExp = match(str.c_str(), pattern);
See here for the reason why.
The problem is that a string literal should be only assigned to a pointer of a const char, so you need to change match to take a char const* pattern (which should be possible when you pass a string literal)
Make 2 parameter of function match const char *, warning is because of it
I have followed the code example here
toupper c++ example
And implemented it in my own code as follows
void CharString::MakeUpper()
{
char* str[strlen(m_pString)];
int i=0;
str[strlen(m_pString)]=m_pString;
char* c;
while (str[i])
{
c=str[i];
putchar (toupper(c));
i++;
}
}
But this gives me the following compiler error
CharString.cpp: In member function 'void CharString::MakeUpper()':
CharString.cpp:276: error: invalid conversion from 'char*' to 'int'
CharString.cpp:276: error: initializing argument 1of 'int toupper(int)'
CharString.cpp: In member function 'void CharString::MakeLower()':
This is line 276
putchar (toupper(c));
I understand that toupper is looking for int as a parameter and returns an int also, is that the problem? If so how does the example work?
Also,
char* str[strlen(m_pString)];
int i=0;
str[strlen(m_pString)]=m_pString;
is not valid C++ - arrays must be dimensioned using compile time constants - this is a C99 feature. And I really don't think the code would do what you want it to, even if it were legal, as you seem to be accessing one past the end of the array. It would be handy if you posted the complete class definition.
I don't think your code does what you want it to do and in fact if it compiled it would explode.
char* str[strlen(m_pString)]; // you've made an array of X C strings where
// X is the length of your original string.
int i=0;
str[strlen(m_pString)]=m_pString; // You've attempted to assign the C string in your array
// at location X to point at you m_pString. X is the
// same X as before and so is 1 past the end of the array
// This is a buffer overrun.
I think what you actually wanted to do was to copy the content of m_pString into str. You'd do that like so:
char * str = new char[strlen(m_pString)];
memcpy(str, m_pString); // I may have the operands reversed, see the docs.
The easier way to do this though is to stop using C strings and to use C++ strings:
std::string str = m_pString;
There are more issues, but this should get you steer you more toward the right direction.
You need to feed toupper() an int (or a char) instead of a char *, which is how you've declared c.
try:
char c;
Also,
char* str[strlen(m_pString)];
is an an array of pointers to characters, not just a single string.
This line:
str[strlen(m_pString)]=m_pString;
is an assignment to a bad pointer then, since there was no allocation.
I'm going to go with the assumption that m_pString is a C style string (char *). You're doing way more fiddling than you need to be doing.
void CharString::MakeUpper()
{
char* str = m_pString; // Since you're not modifying the string, there's no need to make a local copy, just get a pointer to the existing string.
while (*str) // You can use the string pointer as an iterator over the individual chars
{
putchar (toupper(*str)); // Dereference the pointer to get each char.
str++; // Move to the next char (you can merge this into the previous line if so desired, but there's no need.
}
}
In the example you cite, the reason it works is because of how the variables are declared.
int main ()
{
int i=0;
char str[]="Test String.\n"; // This is a compile time string literal, so it's ok to initialize the array with it. Also, it's an array of `char`s not `char*`s.
char c; // Note that this is also a `char`, not a `char *`
while (str[i])
{
c=str[i];
putchar (toupper(c));
i++;
}
return 0;
}
Because of the error-prone ways of using C strings, your best bet is std::string:
void CharString::MakeUpper()
{
string str(m_pString);
transform(str.begin(), str.end(), ostream_iterator<char>(cout), &toupper);
}
There is not a built-in conversion from char * to int, which is why the error occurs. Since you're trying to capitalize a character, you need to dereference the pointer.
putchar(toupper(*c));