Declaration of pointer to an array - access issue - c++

The nearest question on this website to the one I have had a few answers that didn't satisfy me.
Basically, I have 2 related questions :
Q. If I do something like :
char a[]= "abcde"; //created a string with 'a' as the array name/pointer to access it.
a[0]='z'; //works and changes the first character to z.
But
char *a="abcde";
a[0]='z'; //run-time error.
What is the difference? There is no "const" declaration, so I should be free to change contents, right?
Q. If I do something like :
int i[3];
i[0]=10; i[1]=20; i[2]=30;
cout<<*++i; //'i' is a pointer to i[0], so I'm incrementing it and want to print 20.
This gives me a compile-time error, and I don't understand why.
On the other hand, this works :
int *i=new int[3];
i[0]=10; i[1]=20; i[2]=30;
cout<<*++i; //Prints 20.
Thanks for the help.

Q
char *a="abcde";
a[0]='z'; //run-time error.
Ans - Here a is pointing to string literal stored in read only location. You cannot modify string literal
Q
int i[3];
i[0]=10; i[1]=20; i[2]=30;
cout<<*++i;
Ans- Array and Pointers are not same thing. Here i is not a pointer.
You need lvalue for increment operand
You can do :
int *p = &i[0];
std::cout<<*++p;
In last case operator new returns a pointer to a allocated memory space, so its possible.

Question 1
The trouble is that it is still const.
A string literal actually has the type char const*.
But when they designed C++03 they decided (unfortunately) that conversion from char const* to char* is not an error. Thus the code:
char *a="abcde";
Actually compiles without error (even though the string is const). BUT the string literal is still a const even though it is being pointed at via a non const pointer. Thus making it very dangerous.
The good news is that most compilers will generate a warning:
warning: deprecated conversion from string constant to ‘char*’
Question 2
cout<<*++i; //'i' is a pointer to i[0], so I'm incrementing it and want to print 20.
At this point i is not a pointer. It's type is still an array.
It is not a valid operation to increment array.
The thing you are thinking about; is that arrays decay into pointers at the drop of a hat (like when you pass them to functions). Unfortunately that is not happening in this situation and thus you are trying to increment an array (which does not make sense).

Related

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.

How to use strtof endPointer?

Looking at the examples presented by various google results, I don't really understand how the EndPtr works. For an example:
char szOrbits[] = "686.97 365.24";
char* pEnd;
float f1 = strtof (szOrbits, &pEnd);
The function takes the pointer of the pointer that is declared after the char array, does that mean that the actual type and contents of the pointer are irrelevant and the pointer is guaranteed to be allocated right after the array thus making its address the end point?
I tried using it like this:
ret.push_back(EquationPiece(strtof(&Source[mark], (char**)&Source[i])));
where ret is a vector, Source is a char array, mark is where the number begins and i is the next byte after the number but I'm getting some strange results. Is my usage incorrect or should I seek for the bug elsewhere?
Although the reference page describes the parameter pendptr as a reference to a char* object this might be misundestood. In C we have only pointers and the second parameter of strtof is a pointer to a pointer to char.
You can utilize this parameter to get the point in the input char array that could not be used to convert the char array to the output float. If the pointer points to a '\0' than the array has been converted entirely. If it points to something different you can start error handling or further processing of the char array.
You should never cast any pointer when you are not sure what it means. Cast tells the compiler that the programmer knows it better. Depending on the meaning of your EquationPiece it might be useful to pass the endPtr:
ret.push_back(EquationPiece(strtof(&Source[mark], pEnd));

Declaring arrays: name of the array with spaces

I'm trying to understand a part of my professor's code. He gave an example for a hw assignment but I'm not sure how to understand this part of the code..
Here is the code:
void addTask(TaskOrAssignment tasks[], int& taskCount, char *course, char *description, char *dueDate)
{
tasks[taskCount].course = course;
tasks[taskCount].description = description;
tasks[taskCount].dueDate = dueDate;
taskCount++;
}
Question: Is "tasks[taskCount].course = course;" accessing or declaring a location for char course?
I hope I could get this answered and I'm pretty new to this site too.
Thank you.
tasks[taskCount].course = course;
Let's break this down a piece at a time. First of all, we are using the assignment operator (=) to assign a value of one variable to another variable.
The right hand side is pretty simple, just the variable named course which is declared as a char*.
It is assigned to the variable tasks[taskCount].course. If you look at the parameters of the method, you can see that tasks is declared as an array of TaskOrAssignment objects. So tasks[taskCount] refers to one of the elements of this array. The .course at the end refers to a field named course in that object. Assuming that this code compiles, that field is declared as a char* in the TaskOrAssignment class.
Most likely, both course variables represent a string of characters. (This originates from C.) When all is said and done, both course and tasks[taskCount].course point to the same string buffer.
course is a char pointer, it points to the block of memory in stack or heap storing the '\0' terminated string.
tasks[taskCount].course is also a char pointer, the assignment just lets tasks[taskCount].course point to same memory address that course does.
course is a char* (a pointer to char). Presumably, the course member of TaskOrAssignment is also a char*. All that line does is assign the value of course to the member course of the taskCountth element in the array.
Presumably, the course argument is intended to be a pointer to the first character in a null-terminated C-style string. So after this assignment, the course member of the array element will point at that same C-style string. However, of course, the pointer could really be pointing anywhere.

char array - dealing with memory [duplicate]

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

Cannot convert from 'int *' to 'int []'?

I know this might be a common question but I have tried to search but still cannot find a clear answer.
I have the following code:
int* f() {
int a[] = {1,2,3};
return a;
}
int main() {
int a[] = f(); // Error here
getch();
return 0;
}
This code produces the error message: "Cannot convert from 'int *' to 'int []'"
I found this quite strange because I have read that pointer and array are similar. For example, we can use a[i] instead of *(a + i).
Can anyone give me a clear explanation, please?
There are actually two errors in this code.
Firstly, you are returning the address of a temporary (the int array within f), so its contents are undefined after the function returns. Any attempt to access the memory pointed to by the returned pointer will cause undefined behaviour.
Secondly, there is no implicit conversion from pointers to array types in C++. They are similar, but not identical. Arrays can decay to pointers, but it doesn't work the other way round as information is lost on the way - a pointer just represents a memory address, while an array represents the address of a continuous region, typically with a particular size. Also you can't assign to arrays.
For example, we can use a[i] instead of *(a + i)
This, however, has little to do with the differences between arrays and pointers, it's just a syntactic rule for pointer types. As arrays decay to pointers, it works for arrays as well.
The type int[] doesn't actually exist.
When you define and initialize an array like
int a[] = {1,2,3};
the compiler counts the elements in the initializer and creates an array of the right size; in that case, it magically becomes:
int a[3] = {1,2,3};
int[] used as a parameter to a function, instead, it's just plain int *, i.e. a pointer to the first element of the array. No other information is carried with it, in particular nothing about the size is preserved. The same holds when you return a pointer
Notice that an array is not a pointer: a pointer can be changed to point to other stuff, while an array refers always to the same memory; a pointer does not know anything about how big is the space of memory it points to, while the size of an array is always known at compile time. The confusion arises from the fact that an array decays to a pointer to its first element in many circumstances, and passing it to a function/returning it from a function are some of these circumstances.
So, why doesn't your code work? There are two big errors:
You are trying to initialize an array with a pointer. We said that an int * doesn't carry any information about the size of the array. It's just a pointer to the first element. So the compiler cannot know how big a should be made to accomodate the stuff returned by f().
In f you are returning a pointer to a variable that is local to that function. This is wrong, because a pointer does not actually store the data, it only points to where the data is stored, i.e. in your case to the a local to f. Because that array is local to the function, it ceases to exist when the function exits (i.e. at the return).
This means that the pointer you are returning points to stuff that does not exist anymore; consider the code:
int * a = f();
This initialization works, and you can try to use a later in the function, but a will be pointing to the no-longer existent array of f; in the best case your program will crash (and you'll notice immediately that you've done something wrong), in the worst it will seem to work for some time, and then start giving strange results.
int * and int [] are similar but different.
int * is a real pointer, meanwhile int[] is an array reference ( a sort of "constant pointer" to the begin of the data) wich cannot be modified. So, a int * can be threated like a int [] but not viceversa.
You can use a[b] and*(a+b) interchangeably because that is exactly how a[b] is defined when one of a or b is a pointer and the other is of integer or enumeration type.
Note: This also means that expressions like 42[a] are perfectly legal. Human readers might object strongly, but the compiler won't bat an eye at this.