I wrote this short program
int main(){
char * c = "abcd";
c[1] = '\0';
cout << c << endl;
}
and it doesn't work... actually it compiles the program but in the runtime an error occures...
Why? I thought it will print an "a" as the "string" now looks like this: "a0cd" so after a zero it is supposed to detect an end of the string, right? So where is the problem?
Thank you!
You can't modify string literals like that.
Try this instead:
int main(){
char c[] = "abcd";
c[1] = '\0';
cout << c << endl;
}
The reason behind this is that string literals are stored in global memory (often in a read-only segment). Modifying them is undefined behavior. However, if you initialize it as an array char c[] = "abcd" it will be on the stack (as opposed to global memory), so you can freely modify it.
if you use C++ why not use std::string::substr?
#include <iostream>
#include <string>
int main () {
std::string c = "abcd";
std::string d = c.substr(0,2);
std::cout << d << std::endl;
return 0;
}
the output of the program:
ab
Related
I want to implement a simple function that gets a string as a char pointer and modifies the string in a function. The requested function must be void then I have to modify the primary string passed into my function. I got an access violation error and googled it but nothing helped.
My sample code is here:
#include "iostream"
using namespace std;
void FindCommonStr(char*& Common,int &A)
{
int i=0;
while(1)
{
if(Common[i]=='\0')
break;
i++;
}
cout<<"Number of Elements = "<<i<<endl;
for (int j=0 ; j<i-1;j++)
Common[j]='y';
A=2;
}
void main()
{
int A=0;
char* Common = new char;
Common = "Hello World!";
cout<<"Common0 = "<< Common<<endl;
cout<<"A0 = "<< A<<endl;
FindCommonStr(Common,A);
cout<<"Common1 = "<< Common<<endl;
cout<<"A1 = "<< A<<endl;
}
Actually the problem occured in this part of FindCommonStr funtion:
for (int j=0 ; j<i-1;j++)
Common[j]='y';
If I comment this part everything works but I cannot change the string values. I also tested the pointer to pointer solution by defining the function as:
FindCommonStr(char **Common,...
It doesn't help though and I got the violation error again.
Is it even possible to do such a thing?
When you do this:
Common = "Hello World!";
you are making the pointer Common point at a literal C-style string (and incidentally leaking the original char that you allocated via new previously). It is not valid to try to modify such a literal, so when you pass this to FindCommonStr and try to modify it you get an access violation.
You should avoid using C-style strings and use proper C++ std::string instead - this will save a lot of problems and is much more robust, as well as being more appropriate for C++ programming.
Fixed version of your code:
#include <iostream>
#include <string>
using namespace std;
static void FindCommonStr(string &Common, int &A)
{
int i = 0;
while (1)
{
if (Common[i] == '\0')
break;
i++;
}
cout << "Number of Elements = " << i << endl;
for (int j = 0; j < i - 1; j++)
Common[j] = 'y';
A = 2;
}
int main()
{
int A = 0;
string Common = "Hello World!";
cout << "Common0 = " << Common << endl;
cout << "A0 = " << A << endl;
FindCommonStr(Common, A);
cout << "Common1 = " << Common<<endl;
cout << "A1 = " << A << endl;
return 0;
}
Alternatively if this is a homework assignment where you are required to use C strings for some unfathomable reason then a fixed version using only char * strings might look like this:
#include <iostream>
using namespace std;
static void FindCommonStr(char *Common, int &A)
{
int i = 0;
while (1)
{
if (Common[i] == '\0')
break;
i++;
}
cout << "Number of Elements = " << i << endl;
for (int j = 0; j < i - 1; j++)
Common[j] = 'y';
A = 2;
}
int main()
{
int A = 0;
char Common[] = "Hello World!";
cout << "Common0 = " << Common << endl;
cout << "A0 = " << A << endl;
FindCommonStr(Common, A);
cout << "Common1 = " << Common<<endl;
cout << "A1 = " << A << endl;
return 0;
}
This part is conceptually wrong:
char* Common = new char;
// 'Common' is set to point to a piece of allocated memory
// (typically located in the heap)
Common = "Hello World!";
// 'Common' is set to point to a constant string
// (typically located in the code-section or in the data-section)
You are assigning variable Common twice, so obviously, the first assignment has no meaning.
It's like writing:
int i = 5;
i = 6;
On top of that, you "lose" the address of the allocated memory block, so you will not be able to release it at a later point in the execution of your program.
You seem to mixup char[] and string
When you write
char* Common = new char;
you allocate space on the heap for one character which Common is pointing to.
Then you write
Common = "Hello World!";
which sets the pointer Common to point to the string "Hello World" in read-only memory. The heap you allocated previously is now leaked.
There are basically two approaches:
Either you work with arrays of characters, in that case you write something like
char* Common = new char[strlen("Hello World!")+1];
strcpy(Common, "Hello World!");
Now common still points to the heap and the string has been copied there. The extra +1 byte is to hold the ending \0 string terminator.
You need to free the memory Common points to once you are done.
delete Common;
The other approach is to use the string template
std::string Common;
this allows you to assign a string, it capsules all the work with the heap array above.
Common = "Hello World!";
and there is no need to delete anything afterwards since std::string will do that for you.
I was experimenting with C++ and I decided to try the is_big_endian code, in much the same way I would do it in C. However I am getting no output when I try to print out the value of the pointer. I tried both the C and C++ style casts. What am I doing wrong?
#include <iostream>
using namespace std;
int main (void){
int num = 1;
char *ptr = (char *)#
//char *ptr = reinterpret_cast<char *>(&num);
cout << "Value is: " << *ptr << endl;
}
operator<< sees that you are outputting a char, so it prints it as a character, not as a number (it's as if in C you wrote %c instead of %d in a printf); and since *ptr will either be 0 or 1, you'll end up in both cases with a non-printable character.
To fix this, cast explicitly *ptr to int:
cout << "Value is: " << int(*ptr) << endl;
Take the following program:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a[8] = "Hello, ";
char b[7] = "world!";
strcat(a, b);
cout << a;
return 0;
}
Notice that a and b have the same size as their assigned strings.
The documentation states that for strcat(a, b) to work, a needs to be large enough to contain the concatenated resulting string.
Nevertheless, cout << a displays "Hello, world!". Am I entering undefined behavior?
"Am I entering undefined behavior?"
Yes. A region at the end of a[] has been written over. It worked, this time, but might have belonged to something else.
Here I use a struct to control memory layout, and demonstrate it:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
struct S {
char a[8];
char b[5];
char c[7];
};
S s;
strcpy( s.a , "Hello, " );
strcpy( s.b , "Foo!" );
strcpy( s.c , "world!" );
strcat(s.a, s.c);
cout << s.a << endl;
cout << s.b << endl;
cin.get();
return 0;
}
This outputs:
Hello, world!
orld!
Instead of:
Hello, world!
Foo!
The strcat() has stomped all over b[].
Please note that in a real life example such bugs may be far more subtle, and lead you to wondering why perfectly innocent function calls 250 lines later crash and burn horribly. ;-)
EDIT: May I also recommend that you use strcat_s, instead? Or, even better, std::strings:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string a = "Hello, ";
string b = "world!";
a = a + b;
cout << a;
}
Am I entering undefined behavior?
Yes.
If the documentation says "a needs to be large enough to contain the concatenated resulting string", why don't you simply believe it? What is there to doubt?
In your program, array a is not large enough to contain the result. Therefore, your code is wrong and should be fixed. In the words of the standard, you are indeed entering undefined behavior, which means it may work or it may not...
strcat does what is says on the tin viz. copies b onto the end of a without any care as to what data is already there. Since both variables are on the stack one after the other things work. But try
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a[8] = "Hello, ";
int i = 10;
char b[7] = "world!";
strcat(a, b);
cout << a << i;
return 0;
}
And you will probably get an unexpected result since your stack has been corrupted by strcat
That is correct.... The behavior is undefined. Just because you got that answer does not mean that it will not crash next time since the array a is too small.
I am making a C++ program and I have a warning that keeps cropping up (I'm using g++):
warning: pointer to a function used in arithmetic [Wpointer-arith]
and I want to know: what exactly does this warning message mean? What is my compiler trying to tell me the problem is (in general terms) so I can better understand what I'm doing wrong?
Google searches turn up specific solutions to specific problems in people's code, but never tell me exactly what this warning message is trying to say.
I'm just learning arrays and I'm trying to make a program that prints "Hello, world!" one character at a time, each character being stored individually in an array and pumped to cout in a for loop.
Here is the code:
#include <iostream>
using namespace std;
int ARRAY_ELEMENTS = 14;
void greeting()
{
char greeting[ARRAY_ELEMENTS];
greeting[0] = 'H';
greeting[1] = 'e';
greeting[2] = 'l';
greeting[3] = 'l';
greeting[4] = 'o';
greeting[5] = ',';
greeting[6] = ' ';
greeting[7] = 'w';
greeting[8] = 'o';
greeting[9] = 'r';
greeting[10] = 'l';
greeting[11] = 'd';
greeting[12] = '!';
greeting[13] = '\0';
}
int main(int argc, char* argv[])
{
greeting();
for (ARRAY_ELEMENTS = 0;
ARRAY_ELEMENTS <= 13;
ARRAY_ELEMENTS++)
{
cout << greeting[ARRAY_ELEMENTS] << endl;
}
return 0;
}
Thank you for your time.
On this line:
cout << greeting[ARRAY_ELEMENTS] << endl;
you are referring to the function named greeting that you're treating as if it were an array.
greeting is a function, but you try to print it out like it's a char array. It doesn't help the clarity of your code that the function greeting() contains a char array by the same name - this is probably where you've gotten confused. If you give things distinct names, it would be more obvious what's going wrong.
You need to have your greeting() function return something, rather than just fill in a local array, which will not be accessible from outside of the function (and in any event will be discarded as soon as the function returns).
The statement greeting[ARRAY_ELEMENTS] doesn't do what you think it does.
From inside main the name greeting refers to the function void greeting(). You seem to be trying to print the char greeting[ARRAY_ELEMENTS] variable. But you cannot do that from main since that name is only visible from inside void greeting().
You should rename either the function or the variable to ensure that this confusion does not happen again, and beyond that you you have two options: Either ove the loop inside the function greeting or pass a pointer to a buffer into which the greeting must be set into the function. This might be a little more advanced than your current level but you will have to learn how to do it eventually, so no time like the present.
const int ARRAY_ELEMENTS = 14;
void make_greeting(char *greeting)
{
greeting[0] = 'H';
greeting[1] = 'e';
...
}
int main(int argc, char **argv)
{
char buffer[ARRAY_ELEMENTS];
make_greeting(buffer);
std::cout << "The greeting is \"" << buffer << "\"" << std::endl;
for(int i = 0; i != ARRAY_ELEMENTS; i++)
std::cout << "At position " << i << ": '" << buffer[i] << "'" << std::endl;
}
Of course, you should probably just be using std::string instead of character buffers anyways.
I think the problem here is that this code
greeting[ARRAY_ELEMENTS]
doesn't do what you think it does. This tries to index into position ARRAY_ELEMENTS of the function greeting, which isn't a function. The error you're getting is caused by the compiler thinking you're trying to treat greeting as an array, which isn't what you want to do.
There isn't a direct fix for this, but you could consider doing one of the following:
Change greeting to actually be an array.
Make greeting a function that takes in an index and produces the appropriate array value.
Hope this helps!
Consider
#include <string>
#include <iostream>
int main()
{
/*
hello
5
hel
3
*/
char a[] = "hello";
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
a[3] = 0;
std::cout << a << std::endl;
std::cout << strlen(a) << std::endl;
/*
hello
5
hel o
5
*/
std::string b = "hello";
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
b[3] = 0;
std::cout << b << std::endl;
std::cout << b.length() << std::endl;
getchar();
}
I expect std::string will behave identical to char array a. That's it, insert null character in the middle of the string, will "terminate" the string. However, it is not the case. Is my expectation wrong?
A std::string is not like a usual C string, and can contain embedded NUL characters without problems. However, if you do this you will notice the string is prematurely terminated if you use the .c_str() function to return a const char *.
No - std::strings are not NUL-terminated like C "strings"; the std::string records its length independently.
#Lou is right: don't do that. Instead, do this:
b.erase (3, b.length());
Yes, your expectation is wrong. std::string is meant to be different from C strings (e.g. not necessarily stored in consecutive memory / an array).
To duplicate the first section's behavior, try std::cout << b.c_str() instead of std::cout << b.
I expect std::string will behave identical to char array a.
Why? Nothing in the documentation, anywhere, having to do with std::string says it does this.
My suggestion, stop treating like C++ as C plus some stuff.