I'm trying to set a pointer array to a char array in class Tran, however it only applies the first letter of the string. I've tried many other ways but can't get the whole string to go into name.
edit: name is a private variable
char name[MAX_NAME + 1];
Trying to output it using cout << name << endl;
the input is:
setTran("Birth Tran", 1);
help would be appreciated, thank youu
namee[0] == NULL
name[0] = NULL;
These are bugs. NULL is for pointers. name[0] as well as namee[0] is a char. It may work (by work, I mean it will assign the first character to be the null terminator character) on some systems because 0 is both a null pointer constant and an integer literal and thus convertible to char, and NULL may be defined as 0. But NULL may also be defined as nullptr in which case the program will be ill-formed.
Use name[0] = '\0' instead.
name[0] = *namee;
however it only applies the first letter of the string.
Well, you assign only the first character, so this is to be expected.
If you would like to copy the entire string, you need to assign all of the characters. That can be implemented with a loop. There are standard functions for copying a string though; You can use std::strncpy.
That said, constant length arrays are usually problematic because it is rarely possible to correctly predict the maximum required size. std::string is a more robust alternative.
The underlying issue you are trying to assign a const char* to an char* const. When declaring
char name[MAX_NAME + 1];
You are declaring a constant memory address containing mutable char data (char* const). When you are passing a const char* to your function, you are passing a mutable pointer containing constant data. This will not compile. You should be doing a deep copy of the char array by using:
strcpy_s(dst, buffer_size, src);
This copy function will make sure that your array does not overflow, and that it is null terminated.
In order to be able to assign a pointer to a char array, it would need to be allocated on the heap with
char* name = new char[MAX_NAME + 1];
This would allow assigning a char* or char* const to it afterwards. You however need to manage the memory dynamically at this point, and I would advise against this in your case, as passing "Birth Tran" would lead to undefined behaviours as soon as char* const namee goes out of scope.
Related
Why can we do:
char* array = "String";
but not
int* array = 1;
To my understanding * means address, so I don't really understand why we can give a non-address value, like "String." to char* array.
char* array means that array is a variable that can hold the address of another object (such as another variable or constant).
If the program has "String", it means that there is actually an array of 7 characters that exists in memory somewhere and it holds the contents "String".
When you write array = "String"; then the variable array is made to hold the address of the letter 'S' in that string.
This is because C++ has a rule, sometimes called array-pointer decay which means that if you try to use an array (such as "String") in a context where a value is expected, then it gets automatically converted to a pointer to the first element of that array.
Without that rule you'd have to write array = &("String"[0]); . The rule was included in C originally to avoid having to write &....[0] all over the place when working with arrays, although in hindsight it seems to have generated more pain than pleasure.
Moving onto int* i = 1. You have said that i can hold the address of an int, but you have not provided any such address. Variables thare aren't arrays don't automatically get converted to their address. In fact 1 isn't even a variable. We call it a prvalue , it doesn't have any memory storage area associated with it, so it does not have an address. To point at an instance of a 1 you would have to make a variable, for example:
int j = 1; int* i = &j;
* does not mean adress. Its meaning is context sensitive, but most of the time it means pointer.
The reason for this, not to work is because "String" is an array of characters, or a pointer to an character. In contrast to this, 1 is a literal which is not a valid adress. You should write int array = 1 instead, and after that you could do int *brray = &array.
* means a pointer, not an address. You can retrieve an address using the & operator.
char* array = "String";
Actually declares array as a pointer to a character, and the = sign after the declaration tells the compiler what value should the pointer posses. In this case it's an address of "String" in the string pool somewhere in the memory of the run program.
int* array = 1;
Doesn't put the address of 1 to array as you may expect. However, with a little adjustment
int* array = (int*)1;
... it could point to an integer at address 1, which is unfortunately unaccessible.
This assignment:
char* array = "String";
Assign "String" to an available location in memory and returns the memory address of the first position of "String" in memory. "array" stores the address of "S".
This assignment:
int* array = 1;
Doesn't work because you are trying to assign an integer to a pointer to integer. The types are different
"I don't really understand why we can give a non-address value, like "String." "
That's because a character string literal actually is const char[] array, which decays to a pointer when assigned to a char*, while 1 isn't one and you can't take it's address in any way.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why can't I edit a char in a char*?
char *k ;
void ffill()
{
char *d="ddddd";
*k=*d; //expecting to copy "ddddd" to *k
cout<<k<<"\n";
*d[1]=5; // trying to change array element
cout<<k<<"\n";
}
int _tmain(int argc, _TCHAR* argv[])
{
ffill();
cout<<k<<"\n";
}
procedure fill initializes character array k with help of local variable. I'm not sure it copies "ddddd" variable pointer (that is wrong, because after automatic destruction of d memory is not safe) or it copies value and after this *k is initialized correctly.
How to aces *d array element? Compiler is not happy about *d[1]=5;
(Disclaimer: this answer only covers C++. It is not recommended to ask for both C and C++, as both languages are quite different)
Prologue
char *k ;
This declares a pointer to a character.
"ddddd"
This expression has type char const[6], that is, an array of six constant characters. Expressions of this type can be implicitly converted to a pointer to the first element of the array. The type of that pointer is char const*, that is, a pointer to a constant character. A char const* is not convertible to a char*, because char* permits modification of the character it points to, while char const* doesn't.
char *d="ddddd";
Due to the rules outlined above, this statement is not correct. You should turn on the warnings on your compiler and it will warn you against this (ideally it would actually be an error, not just a warning). It should be char const* d = "ddddd"; if you really want a pointer or char d[] = "ddddd"; if you want an array. The second form doesn't need const because it makes a copy, and thus runs no risk of changing the original data, which is const.
*d
This expression involves the implicit conversion to char const* mentioned above, and then the indirection operator (the *) is applied to it, resulting in an expression of type char const&, that is, a reference to a constant character.
*k
Similar to *d, this performs indirection on a pointer. In this case, k is of type char*, so the resulting expression has type char&.
*k=*d; //expecting to copy "ddddd" to *k
The assignment assigns a single character, because it's assignment from a reference to a constant character into a reference to a character. It ends up assigning the first character of the string to the character pointed by k, which is... wait.
Where does k point to? It was never initialized! This is bound to end in tragedy.
Chapter 1
So, how do we get k to point somewhere? And how do we copy the whole string from d into that space?
To copy the six characters of the d array into k, we need space for six characters. The simplest way of doing this is to just make an array of six characters.
char k[6];
Now, how to copy the six elements? We can use the C library function strcpy, which copies null-terminated strings. This function needs a lot of care to use because:
It requires the source to have a null ('\0') character marking the end; if the source does not have such a character, the behaviour is undefined and anything can happen. This is why the string "ddddd" has six characters and not 5: there's an implicit \0 character at the end that the compiler inserts for you.
It requires the destination to have enough space for the whole source string including the null terminator. If the destination doesn't have enough space, the behaviour is also undefined and anything can happen.
This is how this function could be used to make a copy of the string:
std::strcpy(k, d);
Failure to meet either point #1 or #2 can result in anything, from the program seemingly working (if you're unlucky), to acting randomly in strange way, to simply crashing (if you're lucky).
Epilogue
Man, that was a lot of information. Do C++ programmers have to care about these matters all the time? That must be tiresome.
Well, C++ programmers can use std::string instead of character arrays and get a lot less hassle with this: we can make copies with the assignment operator, we don't need to track the correct sizes, we don't need to care for having the null terminators in place, we don't need to limit the size at compile time, and a bunch of other advantages.
std::string k;
void ffill()
{
std::string d="ddddd";
k = d;
cout<<k<<"\n";
d[1]=5;
cout<<k<<"\n";
}
With C programming langage, you should use an array rather than a pointer (because it may point to a read-only string). For example :
char *k;
void
fill(void)
{
char d[] = "ddddd";
k = d;
d[1] = '5'; // Did you mean '5' ?
}
Like Martinho Fernandes already stated: It seems like you're trying to use 'std:string', instead of char arrays.
char k[20] ; //*k doesn't allocate any memory for you to use.
void ffill()
{
char *d="ddddd"; //This works, since it points to the constant character string in your code. But it can not be altered in any way. (It's a 'const char *')
strcpy(k, d); //This standard function copies the content of one pointer to another.
cout<<k<<"\n"; //Not too sure, but it should work,
k[1]=5; //k is the 'changeable memory, not 'd'.
cout<<k<<"\n";
}
There are several things going on here that you need to be aware of. Let me try to explain:
char *k ;
This line declares a variable called k which is a pointer to a character. However, it is not initialized to point to anything. Trying to use an uninitialized pointer will result in undefined behavior.
void ffill()
{
char *d="ddddd";
This line declares a variable named d which is also a pointer to a character. At the same time, you initialize the pointer to point to a constant character array (also called a c-string) that contains 5 'd' characters and a terminating NULL character (so the array has 6 elements).
*k=*d; //expecting to copy "ddddd" to *k
This line uses the dereference operator (*). This operator copys the character pointed to by d and places it at the address pointed to by k. As I noted above, this will result in undefined behavior since the address in the pointer k has not been initialized.
cout<<k<<"\n";
*d[1]=5; // trying to change array element
First of all, you are trying to assign an int to a char. Both C and C++ allow this, but you probably won't get what you expect. In this case, you are trying to replace the second 'd' character with the character code 5. In ASCII, this is a non-printing character.
Also, since d points to a c-string constant, trying to change its elements results in undefined behavior.
cout<<k<<"\n";
}
int _tmain(int argc, _TCHAR* argv[])
{
ffill();
cout<<k<<"\n";
}
There are some other issues with copying one c-string to another, but this is all the detail I will go into here. As other people mention, using std::string is simpler. However, I also believe that learning how to use c-strings is very educational and can improve your coding skills.
Let's see:
*k=*d; //expecting to copy "ddddd" to *k
This won't copy the "string", only tries to set the memory pointed by k to the first character of d. If it is not initialized, then it will fail badly.
*d[1]=5; // trying to change array element
This will also fail. First of all, this is a double indirection. The d[1] = 5; would be betted, but that would also fail, because the string is most probably stored in read-only memory.
Use string instead.
You need to declare d as an array and not a pointer.:
char d[]
d[1] = '5'; // d is a char array, so did you mean the character '5'?
And change
*k=*d; to k = d; //This will copy the value of the pointer
I have a few questions I would like to ask about string literals and C-strings.
So if I have something like this:
char cstr[] = "c-string";
As I understand it, the string literal is created in memory with a terminating null byte, say for example starting at address 0xA0 and ending at 0xA9, and from there the address is returned and/or casted to type char [ ] which then points to the address.
It is then legal to perform this:
for (int i = 0; i < (sizeof(array)/sizeof(char)); ++i)
cstr[i] = 97+i;
So in this sense, are string literals able to be modified as long as they are casted to the type char [ ] ?
But with regular pointers, I've come to understand that when they are pointed to a string literal in memory, they cannot modify the contents because most compilers mark that allocated memory as "Read-Only" in some lower bound address space for constants.
char * p = "const cstring";
*p = 'A'; // illegal memory write
I guess what I'm trying to understand is why aren't char * types allowed to point to string literals like arrays do and modify their constants? Why do the string literals not get casted into char *'s like they do to char [ ]'s? If I have the wrong idea here or am completely off, feel free to correct me.
The bit that you're missing is a little compiler magic where this:
char cstr[] = "c-string";
Actually executes like this:
char *cstr = alloca(strlen("c-string")+1);
memcpy(cstr,"c-string",strlen("c-string")+1);
You don't see that bit, but it's more or less what the code compiles to.
char cstr[] = "something"; is declaring an automatic array initialized to the bytes 's', 'o', 'm', ...
char * cstr = "something";, on the other hand, is declaring a character pointer initialized to the address of the literal "something".
In the first case you are creating an actual array of characters, whose size is determined by the size of the literal you are initializing it with (8+1 bytes). The cstr variable is allocated memory on the stack, and the contents of the string literal (which in the code is located somewhere else, possibly in a read-only part of the memory) is copied into this variable.
In the second case, the local variable p is allocated memory on the stack as well, but its contents will be the address of the string literal you are initializing it with.
Thus, since the string literal may be located in a read-only memory, it is in general not safe to try to change it via the p pointer (you may get along with, or you may not). On the other hand, you can do whatever with the cstr array, because that is your local copy that just happens to have been initialized from the literal.
(Just one note: the cstr variable is of a type array of char and in most of contexts this translates to pointer to the first element of that array. Exception to this may be e.g. the sizeof operator: this one computes the size of the whole array, not just a pointer to the first element.)
char cstr[] = "c-string";
This copies "c-string" into a char array on the stack. It is legal to write to this memory.
char * p = "const cstring";
*p = 'A'; // illegal memory write
Literal strings like "c-string" and "const cstring" live in the data segment of your binary. This area is read-only. Above p points to memory in this area and it is illegal to write to that location. Since C++11 this is enforced more strongly than before, in that you must make it const char* p instead.
Related question here.
I know they are different, I know how they are different and I read all questions I could find regarding char* vs char[]
But all those answers never tell when they should be used.
So my question is:
When do you use
const char *text = "text";
and when do you use
const char text[] = "text";
Is there any guideline or rule?
As an example, which one is better:
void withPointer()
{
const char *sz = "hello";
std::cout << sz << std::endl;
}
void withArray()
{
const char sz[] = "hello";
std::cout << sz << std::endl;
}
(I know std::string is also an option but I specifically want to know about char pointer/array)
Both are distinctly different, For a start:
The First creates a pointer.
The second creates an array.
Read on for more detailed explanation:
The Array version:
char text[] = "text";
Creates an array that is large enough to hold the string literal "text", including its NULL terminator. The array text is initialized with the string literal "text".The array can be modified at a later time. Also, the array's size is known even at compile time, so sizeof operator can be used to determine its size.
The pointer version:
char *text = "text";
Creates a pointer to point to a string literal "text". This is faster than the array version, but string pointed by the pointer should not be changed, because it is located in an read only implementation defined memory. Modifying such an string literal results in Undefined Behavior.
In fact C++03 deprecates use of string literal without the const keyword. So the declaration should be:
const char*text = "text";
Also,you need to use the strlen() function, and not sizeof to find size of the string since the sizeof operator will just give you the size of the pointer variable.
Which version is better?
Depends on the Usage.
If you do not need to make any changes to the string, use the pointer version.
If you intend to change the data, use the array version.
EDIT: It was just brought to my notice(in comments) that the OP seeks difference between:
const char text[] and const char* text
Well the above differing points still apply except the one regarding modifying the string literal. With the const qualifier the array test is now an array containing elements of the type const char which implies they cannot be modified.
Given that, I would choose the array version over the pointer version because the pointer can be(by mistake)easily reseated to another pointer and the string could be modified through that another pointer resulting in an UB.
Probably the biggest difference is that you cannot use the sizeof operator with the pointer to get the size of the buffer begin pointed to, where-as with the const char[] version you can use sizeof on the array variable to get the memory footprint size of the array in bytes. So it really depends on what you're wanting to-do with the pointer or buffer, and how you want to use it.
For instance, doing:
void withPointer()
{
const char *sz = "hello";
std::cout << sizeof(sz) << std::endl;
}
void withArray()
{
const char sz[] = "hello";
std::cout << sizeof(sz) << std::endl;
}
will give you very different answers.
In general to answer these types of questions, use the one that's most explicit.
In this case, const char[] wins because it contains more detailed information about the data within -- namely, the size of the buffer.
Just a note:
I'd make it static const char sz[] = "hello";. Declaring as such has the nice advantage of making changes to that constant string crash the program by writing to read-only memory. Without static, casting away constness and then changing the content may go unnoticed.
Also, the static lets the array simply lie in the constant data section instead of being created on the stack and copied from the constant data section each time the function is called.
If you use an array, then the data is initialized at runtime. If you use the pointer, the run-time overhead is (probably) less because only the pointer needs to be initialized. (If the data is smaller than the size of a pointer, then the run-time initialization of the data is less than the initialization of the pointer.) So, if you have enough data that it matters and you care about the run-time cost of the initialization, you should use a pointer. You should almost never care about those details.
I was helped a lot by Ulrich Drepper's blog-entries a couple of years ago:
so close but no cigar and more array fun
The gist of the blog is that const char[] should be preferred but only as global or static variable.
Using a pointer const char* has as disadvantages:
An additional variable
pointer is writable
an extra indirection
accessing the string through the pointer require 2 memory-loads
Just to mention one minor point that the expression:
const char chararr[4] = {'t', 'e', 'x', 't'};
Is another way to initialize the array with exactly 4 char.
String data
What I am particularly confused about is this statement
"Its contents are guaranteed to remain unchanged only until the next call to a non-constant member function of the string object."
Can someone clarify what does this mean? When to use this and when to avoid using this?
They mean that you could store the pointer and use it later. If some non-const method is called between two accesses the contents of the buffer your stored pointer is set to may change and your will face unexpected behaviour.
const char* data() const;
This is saying that the const char * returned by calling str.data() will not change unless someone modifies the string that it came from. Once someone calls a non-constant member function, the returned pointer could be invalid, or could point to different data from what it pointed to immediately after the str.data() function returned.
It means you can pass the returned data to C functions, for example. It means you should not do something like:
const char *old = str.data();
size_t len = str.length();
...call a function that modifies str...
// cout << old << endl;
// Since old is not guaranteed to be null terminated (thanks MSalter),
// do something else with the old data instead of writing to cout.
// Inventiveness not at a high this morning; this isn't a particularly
// good example of what to do - a sort of string copy.
char buffer[256];
memcpy(buffer, old, MIN(sizeof(buffer)-1, len));
buffer[len] = '\0';
By the time the I/O memory copying is done, old may not be valid any more, and len may also be incorrect.
Sometimes, you need to have access to the string formatted as an array of characters - usually because you need to pass the string to some function which expects the string like this (for example strcmp). You can do this by using the data or c_str members, but you have to respect the rules for calling the function which are spelled out plainly in the link you provided:
The returned array points to an
internal location which should not be
modified directly in the program. Its
contents are guaranteed to remain
unchanged only until the next call to
a non-constant member function of the
string object.
You cannot modify the array of characters - the string object assumes that you do not, and if you do this will lead to undefined behaviour.