C++ Array Inquiry - c++

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.

Related

Pointer value to array C++

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.

C++: Why can't I convert a string to C-string with an initializer char foo[]?

This is my code:
const char readArr[] = readWord.c_str();
This gives an error: array initializer must be an initializer list or string literal
Why must I use
const char *readArr = readWord.c_str();?
It's for the same reason you can't
const char *p="foo";
const char readArr[]=p;
either. An array is not a discrete object that can be initialized. The only thing that can be initialized in C++ is a discrete object, and an array is not an object per se. An array is a conceptual address of a contiguous list of values, in consecutive memory locations. When an array is used in an expression, such as:
readArr[i]
The array's name decays to a pointer to the first element in the array. Now, guess what you did when you wrote this:
const char *readArr = readWord.c_str();
Well, you just stored a pointer to the first element in an array of characters, that's owned by the readWord std::string.
In a regular array declaration:
char readArr[]="Hello";
the compiler is given the length of the string, and thus it initialize a consecutive list of character values, and the label readArr to it.
const char readArr[] = readWord.c_str();
The reason this is not legal is that it simply doesn't make sense to initialise an array from a pointer. A pointer is in essence a memory address: it points to some data, whether that data is dynamically or statically allocated (allocated 'on the heap' or 'on the stack' respectively). A pointer does not record how much memory is there.
This is confusing to newcomers to C and C++ because the language often allows you to treat arrays as if they were just pointers to their first element. That doesn't mean that arrays are just pointers to their first element. They aren't. But if you use them in an expression they will decay to a pointer to their first element.
Because arrays are not pointers. An array... is an array, period. char readArr[] (just like char arr[4]) declares something directly in the local memory space (the stack, for a function) so that something has to be statically allocated.
str.c_str() is somewhere on the heap so that can't work.

Trouble with C++ Pointers

If you have a look at the code
#include <iostream>
enum Type
{
INT,
FLOAT,
STRING,
};
void Print(void *pValue, Type eType)
{
using namespace std;
switch (eType)
{
case INT:
cout << *static_cast<int*>(pValue) << endl;
break;
case FLOAT:
cout << *static_cast<float*>(pValue) << endl;
break;
case STRING:
cout << static_cast<char*>(pValue) << endl;
break;
}
}
int main()
{
int nValue = 5;
float fValue = 7.5;
char *szValue = "Mollie";
Print(&nValue, INT);
Print(&fValue, FLOAT);
Print(szValue, STRING);
return 0;
}
The line char *szValue = "Mollie";is what confuses me. From what I have been learning is that a pointer is a variable that holds the address of another variable. My issues with that line obviously is that
How come this code accepts a string into a char? We have not specified that this char is an array. Then how come?
How come we are assigning a STRING to a pointer? I thought we could only assign other addresses to them. Where is that pointer getting its address from? Where is it storing the value?
I am still new to C++ but any help would be appreciated.
Update: from what I have understood from the answers below is that when we say "it assigns each letter to the memory addresses in the vicinity of szValue". The rest of the Chars in the string are stored in +1 addresses. How does C++ know how many char / addresses are in the original string? Since szvalue only contains the address of the first char. Not the others right?
Source: LearnCPP - Void Pointers
In a nutshell, in C++ pointers and arrays are almost the same thing. For compiler there is no difference when you define *szValue or szValue[].
A string literal is stored by compiler in memory and first symbol address is actually the value of the string. When you assign a string to char * you might get different use of the that block of memory (i.e. just pass this address into some function or iterate over symbols)
Mind examining more pages of the online tutorial you found pointers-arrays-and-pointer-arithmetic. However I consider the best for learning C++ is reading Bjarne Stroustrup
EDIT: (credits to seand)
Pointers and arrays are almost, but not exactly the same. Take, char *x, and char y[5]. 'y' is like a pointer that points to something fixed, but 'x' may be reassigned. sizeof y yields 5. When passing x or y into functions the arrayness of 'y' disappears
How come we are assigning a STRING to a pointer? I thought we could only assign other addresses to them. Where is that pointer getting its address from? Where is it storing the value?
So, two things.
Except when it is the operand of the sizeof or the unary & operators (along with a couple of others), 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 converted ("decay") to an expression of type "pointer toT", and the value of the expression will be the address of the first element of the array.
A string literal is an expression of type "N+1 element array of const char" (plain char in C) where N is the number of characters in the string.
Putting that together,
char *szValue = "Mollie";
the string literal "Mollie" is an expression of type "7-element array of const char". Since it isn't the operand of the sizeof or unary & operators, and since it isn't being used to initialize an array, it is converted to an expression of type "pointer of const char", and its value is the address of the first element.
This is an important point - arrays are not pointers. Arrays do not store a pointer value anywhere. Under certain circumstances the compiler will substitute a pointer expression for an array, but otherwise they're two completely different animals.
The previous two answers have covered the gist of the matter. There are strong similarities between pointers and arrays (arrays can be considered pointers to a memory location themselves). For example, when an array name is used as an argument for a function the memory address of the first element is passed to the function as opposed to the value at that location (which would be the case for an ordinary variable).
The code above assigns a string literal "Mollie" to the char pointer szValue. Therefore starting from the "M" (which is treated as a char not a string) in "Mollie" it assigns each letter to the memory addresses in the vicinity of szValue. Therefore the pointer variable szValue would point to the first element of the string, equivalent to saying szValue[0] (if szValue were declared as a char array).
Hope this helps.
Edit:
Just to be more specific szValue points to the memory address of the first element in the string "Mollie" which is equivalent to using &szValue[0].
The line char* s = "Mollie", in C and C++, means this:
s is a pointer to a character.
It is initialized pointing to the first character in a static character array containing the characters M, o, ... e, and a null character \0.
A pointer is a pointer to a piece of memory containing a type.
That piece of memory is not necessarily a variable.
How come this code accepts a string into a char?
Your code isn't actually doing that, instead it's assigning the address of the first character element to the value of the pointer. Viz, the pointer points to the beginning of the string, incrementing the pointer by 1 will now refer to the next character in the array, and so on.
We have not specified that this char is an array. Then how come?
You have char*, not char, that's the difference. Also, semantically char[] and char* are the same.
Where is that pointer getting its address from?
The compiler sticks the literal string "Mollie" in a read-only portion of the program's memory that is loaded when the program is executed by the operating system. The value of szValue is equal to the address of that string literal. You'll find it's read-only and if you attempt to modify it you'll get a segfault (on *nix) or an Access Violation on Windows.
char *foo declares a char pointer, which in C is how arrays are represented.
So:
char *foo = "ABCD";
foo[1] == 'B'
which also means:
*(foo + 1) == 'B'
The actual type of "Mollie" is const char*. You can think about it as about an array of chars. Thats why you can write something like this:
const char c = szValue[4];
Here, szValue is just a pointer to the first character of the string. Hence, szValue + 1 will be a pointer to the second character and so on.
You should know that when you use char *szValue = "Mollie";, it means you assign the address of constant string "Mollie" to szValue and you can't change value through szValue, because "MOllie" is a constant value stored in constant area.

Understanding C-strings & string literals in C++

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.

initializing char and char pointers

What's the difference between these:
This one works:
char* pEmpty = new char;
*pEmpty = 'x';
However if I try doing:
char* pEmpty = NULL;
*pEmpty = 'x'; // <---- doesn't work!
and:
char* pEmpty = "x"; // putting in double quotes works! why??
EDIT: Thank you for all the comments:
I corrected it. it was supposed to be pEmpty ='x',
So, this line doesn't even compile: char pEmpty ='x';
wheras this line works: char* pEmpty ="x"; //double quotes.
Your second line doesn't work because you are trying to assign 'x' to pEmpty rather than *pEmpty.
Edit: Thanks to Chuck for the correction. It ALSO doesn't work because you need to allocate some memory to hold the value 'x'. See the example below.
The third line does work because you are using an initalizer rather than a regular assignment statement.
In general, you should understand how pointers and dereferencing work.
char *p = new char(); // Now I have a variable named p that contains
// the memory address of a single piece of character
// data.
*p = 'x'; // Here I assign the letter 'x' to the dereferenced value of p;
// that is, I look up the location of the memory address contained
// in p and put 'x' there.
p = 'x'; // This is illegal because p contains a memory address,
// not a character.
char q = 'x'; // Now I have a char variable named q containing the
// character 'x'.
p = &q; // Now I assign the address of q (obtained with the reference
// operator &) to p. This is legal because p contains a memory
// address.
You need to keep in mind what a pointer is — it's just a normal variable that holds an address, much like a char holds a character value. This address can be used to look up another variable (with the * operator).
When you do char* pEmpty = new char, you're giving pEmpty the value returned by new char, which is the address of a chunk of memory large enough to hold a char value. Then you use *pEmpty to access this memory and assign it the char value 'x'.
In the second example, you write pEmpty = 'x' — but remember that pEmpty is a pointer, which means it's supposed to hold an address. Is 'x' an address? No, it's a character literal! So that line isn't really meaningful.
In the third example, you're assigning pEmpty the string literal "x". Is this an address? Yes, it is. The literal evaluates to the address of that constant string.
Remember, pointers are a completely different thing from the type that they point to. They can be used to access a value of that type, but they are a completely different type of their own.
The difference is that string literals are stored in a memory location that may be accessed by the program at runtime, while character literals are just values. C++ is designed so that character literals, such as the one you have in the example, may be inlined as part of the machine code and never really stored in a memory location at all.
To do what you seem to be trying to do, you must define a static variable of type char that is initialized to 'x', then set pEmpty to refer to that variable.
The second example doesn't work for a few reasons. The first one would be that you have made the pointer point to, well, nowhere in particular. The second is that you didn't actually dereference it, so you are telling the pointer to point to the address of a character literal. As it has no address, the compiler will complain.
EDIT:
Just to be clear, the asterisk (*) is the operator that dereferences pointers.
pEmpty = 'x'; assigns pEmpty (rather than the memory pointed by it) the value of 'x'.
*pEmpty = 'x'; //this is probably what you want