I have very basic question. In the below code we are passing string as argument to someFunc function where it takes char array as argument. How will memory get allocated for a[], and where will the memory get allocated ? Also how it will be decided how much memory to allocate in case of different sized strings ?
int someFunc(char a[])
{
//do something
}
int main( )
{
someFunc("Frankenstein is dead");
someFunc("Hello there");
return 0;
}
When declaring an argument as an array in C++, it's actually declared as a pointer.
That is, your function is really
someFunc(char* a) { ... }
That means, what is passed is a pointer to the first element of the literal strings.
Also note that in C++ a literal string is an array of constant characters. So it decays to the type const char*. Which means your argument have to be of that type as well.
How the constant string literal arrays are allocated are really irrelevant and an implementation detail, but it's typically the compiler saves the strings together with the generated code in the executable program file. This lets them be loaded into memory by the operating system program loader together with the code, and no "dynamic" allocation for the strings themselves are made.
Related
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.
How to find the size of string array passed to a function. The size should be computed inside the function.
#include<iostream>
using namespace std;
template <typename T,unsigned S>
unsigned arraysize(const T (&v)[S]) { return S; }
void func(string args[])
{
unsigned m=arraysize(args);
cout<<m;
}
int main()
{
string str_arr[]={"hello","foo","bar"};
func(str_arr);
}
What i dont understand is:
If the statement arraysize(str_arr) is used in main,it wouldn't pose a problem. The str_arr is an array, so str_arr acts as a pointer, so when we use arraysize(str_arr) that means we're sending the address to arraysize function.(correct me if i'm wrong).
But in function func(), i dont understand why there is a problem, i.e. the statement arraysize(args) sends the address of the string array args(or the address of pointer args).. or is it more complicated since it becomes some double pointer?? Explain?
Also please correct the above code..
str_arr is an array of strings. When you do sizeof(str_arr), you get the size of that array. However, despite the fact that args looks like an array of strings, it's not. An argument that looks like an array is really of pointer type. That is, string args[] is transformed to string* args by the compiler. When you do sizeof(args) you are simply getting the size of the pointer.
You can either pass the size of the array into the function or take a reference to the array with a template parameter size (as you did with arraysize):
template <size_t N>
void func(string (&args)[N])
{
// ...
}
There is no way to determine the size of an array when sent to a function. You also have to remember that only a pointer to the array is sent to the function, which makes it even theoretically quite implausible to calculate the array's size.
The information of the array's size is never visible in your function, as you threw it away when you decided to use string args[] for the argument. From the compiler's perspective, it's the same as string* args. You could change the function to:
template<size_t M>
void func(string (&args)[M])
{
cout<<M;
}
but it seems you already know that, right?
If the statement arraysize(str_arr) is used in main,it wouldn't pose a
problem. The str_arr is an array, so str_arr acts as a pointer, so
when we use arraysize(str_arr) that means we're sending the address to
arraysize function.(correct me if i'm wrong).
I have to correct you here. You state a correct premise, but draw the wrong conclusion.
The key point is indeed that str_arr is an array in main. While an array decays to a pointer in many (most) expression contexts, this does not apply when a reference to array is initialized. That is the reason why array_size is declared to take a reference to array parameter - this is the only way to have a parameter of array type, which implies that it comes with a defined length.
That is not the case for func. When a function parameter is declared to be of plain array type, the the array to pointer decay is applied to that declaraction. Your declaration of func is equivalent to void func(string * args). Thus args is a pointer, not an array. You could call func as
string str_non_array;
func(&str_non_array);
Because of this, a reference-to-array can't bind to it. And anyways, args has completely lost all information about the size of the array it is pointing to.
You could use the same reference-to-array trick as is used in arraysize: declare func as
template <std::size_t N>
void func(string (&args)[N]);
But this gets impractical to do everywhere (and may lead to code bloat, if applied naively to all array-handling code). The C++ equivalent of an array-with-length as available in other languages is std::vector<string> (for dynamically sized arrays) or std::array<string,N> (for fixed size known at compile time). Note that the latter can cause the same code bloat as mentioned above, so in most cases, std::vector<string> would be the preferred type for array that you need to pass to various functions.
Dmitry is right and I would like to explain it a bit further. The reason its happening is because array is not a First Class citizen in C++ and when passed as parameter it decays to pointer and what you get in called function is a pointer to its first element and size is lost.
You can refer C++ arrays as function arguments to see what alternative options are available.
This question already has answers here:
Why doesn't C++ support functions returning arrays?
(10 answers)
Closed 10 years ago.
I've got a syntax question in C++ about returning an array. When we pass in an array, when can do like this:
void merge_sort(int input_array[], int size);//notice the first parameter
I know this works:
int* merge_sort(int input_array[], int size){
//do something with input_array
return new int[2]; //dummy array
}
Question:
int[] merge_sort(int input_array[], int size){ //Question is on return type, wont compile
//do something with input_array
return new int[2]; //dummy array
}
return int* succeed. Why returning int [] fail?
In both C and C++, you cannot either pass an array as an argument to a function, or return an array as a function result.
Yes, the syntax can make it look like you're passing an array argument:
void func(int param[]) {
// ...
}
...
int arr[10];
func(arr);
but in fact that's just passing a pointer to the array's first element. The parameter definition int param[] is adjusted; it's exactly equivalent to int *param. And an expression of array type, in most contexts, is implicitly converted to a pointer its first element.
That's why you need to pass the size as a separate argument.
Using only C features, there are several ways to do something like returning an array:
A function can return a pointer to the first element of a static array. This has some disadvantages: the size has to be fixed, and multiple callers get pointers to the same object.
A function can receive a pointer to the first element of an array, passed in by the caller. This places the burden of allocating and deallocating the array on the caller.
A function can return a pointer to the first element of a dynamically allocated (malloc() in C, new in C++) array. This requires the caller to deallocate the array.
C++ provides a rich set of library classes that can take care of all this for you.
Recommended reading: Section 6 of the comp.lang.c FAQ.
You can pass structs as arguments, and return them as function results, and structs can contain arrays as members. But that's not as useful as you might think. An array that's a member of a struct must have a fixed size; most useful code that operates on arrays can handle dynamic sizes.
Why would you want to return anything in the first place?
Array is not really "passed" to the function (no copy of the elements is made), only the pointer to it's beginning is. When the function rearranges the array elements, it is doing so in the original array. After the function exits, the calling code can simply continue to use the old (now-sorted) array.
In other words, the function produces a side-effect.
I know this works:
int* merge_sort(int input_array[], int size){
//do something with input_array
return new int[2]; //dummy array
}
(Assuming you actually need to return...)
Well it "works", but is very dangerous. The caller needs to be aware it needs to free the returned array (otherwise a memory leak ensues), and it needs to be aware it must use delete[] and not just delete (otherwise an undefined behavior ensues), which is distinctly non-obvious based only on the return type (which is just a pointer). The caller might also be in doubt whether the input_array is freed inside the function or not.
Even if you have documented all that, it's extremely easy for the caller to make a mistake. It's much better to use the facilities provided by modern C++ instead: for example, you could return an std::vector.
you should be using a vector in this approach, in your project include and then use a vector almost as u would with an array.
u can have a look at vectors here: http://msdn.microsoft.com/en-us/library/vstudio/9xd04bzs.aspx
the great thing about vectors is that they are dynamically scaling for your projects and would not create any memory leaks or such due to buffer overflow's, its much like an ArrayList
When you access elements of an array using array[i], I thought that C++ would take the starting position of the array in memory and add i*sizeof(one array element) and then dereference that address (or do something equivalent to what I just described). However, it seems to me that if you have an array of strings (std::string), each element could be a different size based on the number of characters in the string, so there must be something else going on.
Also, to my understanding, array elements are stored in contiguous memory. If you had strings stored in contiguous memory and then appended more characters to one of them, all of the succeeding strings would have to be moved over.
Can someone explain to me how this works?
The string size is constant, but it (at some level) has a pointer to some non-constant-sized data.
The pointer size is constant, the pointee size is not.
std::strings are objects. The size of one std::string is the same as the size of another std::string. They indirectly "contain" their data via dynamic allocation, which does not affect the size of the owning object.
Similarly, if you mean C-style strings, you actually only pass around char* (or pointers-to-char). Pointers are always the same size, no matter the length of the block of memory to which they point.
std::string is a wrapper of char*, not an array. Arrays can be different sizes, yes, but char*s are pointers and have a constant size. The char* that std::string encapsulates points to dynamically allocated memory. This is why sizeof(std::string) returns the same size no matter how large the string grows.
If you're refering to the C++ type std::string, each one of the elements of an array of strings occupy the same ammount of memory. However, each string may contain a pointer pointing to a different position in the memory, of different length, where it actually stores the string.
To see an example (sample code), imagine the std::string class something like this:
struct string
{
size_t length;
const char* data;
// other members..
};
Note how the structure size is always the same (a size_t and a pointer), but the memory pointed to, where the actual string is stored, may be different.
The string object has a size and that will differ depending on your implementation complier etc. You are correct in your assessment of who c++ handles arrays, but overlook pointer data. The string class in its bowels has a pointer to some heap data that heap data can be of any arbitrary size, but the pointer to that data is a fixed size. So inside the data layout of a string there is a way for the complier to create uniform objects with non fixed representation data.
Since a string is a character pointer, an array of strings is an array of (char *) — a contiguous vector of (char *) pointers. Modifying a string would modify the memory pointed to by each element. Now, if you declared it to be statically allocated:
char foo[10][10];
then in terms of memory layout it's indistinguishable from
char foo2[100];
and it would be possible to corrupt memory by writing past the declared size; this is one reason one should use std::string instead of C-style strings, which are perhaps the best example of why C is a lousy language for application programming. (An array of std::string would be an array of objects, each of which would have a (char *) stored in it somewhere that you wouldn't need to worry about — std::string does it for you, and much more reliably.)
This is how you would do it in code...
const int ARRSIZE = 5;
string arrayOfStr[ARRSIZE] = {"one", "two", "three"};
for (int i = 0; i < ARRSIZE; ++i)
{
cout << arrayOfStr[i] << endl;
}
I have a homework assignment with a number of questions. One is asking why the strcpy() function doesn't need the call by reference operator for CStrings. I've looked through the book numerous times and I can't, for the life of me, find the answer. Can anyone help explain this to me?
It is an array of sorts so I would think you would need the call by reference.
strcpy() takes a pointer to char.
Thus you don't pass the "string" as a parameter but only the address of its first character.
So basically you have something like this:
void func(const char* str);
const char* str = "abc";
func(str); // Here str isn't passed by reference but since str is a pointer to the first character ('a' here), you don't need a reference.
Passing a pointer is fast. On a 32 bits architecture, a pointer takes 32 bits, whatever the length of the pointed string.
If you mean class CString, then in other words the question asks you:
Why does this compile?
CString sExample;
char buffer[LARGE_ENOUGH];
strcpy(buffer, sExample);
The answer is, because class CString defines an operator const char* and therefore can be converted to the type of strcpy's second argument.
I 'm not sure if this is what you mean though.
This a problem of terminology, mostly.
An "object" (I use the term as designing "a chunk of RAM") is passed by value when the called function gets a copy of the chunk. It is passed by reference when the called function gets a way to access the one and only chunk.
Consider this:
void f(int x)
{
x = 42;
}
void g()
{
int y = 54;
f(y);
// here "y" still has value 54
}
Here, the function f() modifies x, but that is its own x, a variable which contains a copy of the contents of the y variable of g(). What f() does with its x does not impact what the y of g() contains. The variable is then passed by value.
C++ has a notion of reference which goes like this:
void f(int& x)
{
x = 42;
}
void g()
{
int y = 54;
f(y);
// here "y" now has value 42
}
Here, the special construction (with the "&") instructs the C++ compiler to play some hidden tricks so that the x known by f() is actually a kind of alias on the y variable used by g(). There is only one variable: the x and the y designate the same chunk of RAM. The variable is here passed by reference.
Now, consider a "C string". In C (and C++), a string is just a bunch of char values, the last of which having value 0 (this is the conventional string terminator). The code does not handle strings directly; it uses pointers. A pointer is a value which actually designates an emplacement in RAM. The pointer is not the string; the pointer is a kind of number (usually on 32 or 64 bits, it depends on the processor type and the operating system) which tells where in RAM is the first char of the string. So when you call strcpy() you actually give it pointers (one for the destination buffer, one for the source string). Those pointers are unmodified: the source string and the destination buffers are not moved in the process; only the contents of the string are copied into the destination buffer.
Hence, strcpy() needs not have access to the variables which contain the pointers in the caller code. strcpy() only needs to know where the destination buffer and the source strings are in RAM. Giving a copy of the pointer values to strcpy() is enough. Hence, those pointers are passed by value.
Note that in the presence of pointers, there are two objects to consider: the variable which contains the pointer, and the chunk of RAM which is pointed to. The pointer itself is passed by value (strcpy() receives its own copy of the variable which contains the pointer to the destination buffer). We can say that the pointed-to chunk of RAM (the destination buffer) is "passed by reference" since it is not duplicated in the process and the called function (strcpy()) can modify it. The point here is that the term "reference" has two distinct meanings:
The C++ syntax meaning: "reference" designates the special construction with the "&" that I have described above.
The language theory formal meaning: "reference" designates a way by which a value is indirectly designated, so that caller and callee may access the same chunk of RAM under distinct names. With that meaning, passing by value a pointer to a called function is equivalent to passing by reference the chunk of RAM to which the pointer points.
A C++ "reference" (first meaning) is a syntaxic way to pass "by reference" (second meaning) a variable.
Well in the case you mean c-strings (char*) you don't need a call by reference because the string itself is a pointer. So string copy knows where to/from where to copy the string.
Because strcpy works with char* which are pointers. The pointer is passed by value, and strcpy uses that pointer to access the indiviual characters in the target string and change them. Compare that to passing an integer by value - the function can't change the original integer.
Understanding how char* strings are not like integers is vital to you not going crazy during your C++ course. Well done for your prof making you face it.
Because in C when calling functions, arrays are passed as the address of the first element, which is equivalent of calling by reference.
See Peter Van Der Linden Expert C programming, Deep secrets book.
automatic type conversion, is the answer I guess they're looking for. Looking that turn up might give you some help.