I will provide some concepts that will potentially help you derive a solution to your problem. Then provide a quick solution that can help you with your final solution.
...If I just assign a = b like this then I get the output 15, 9, 8, 4, 3, 5 with 5 being a garbage value.
The output of the number 5 has nothing to do with your assignment of a=b in fcn02. The value 5 is actually the value of x in the calling function. You are accessing the array outside the bounds of it's original allocation thus accessing the value of next address of the size of int. In this case it's the value of x. if you spit out the address of x and the address of a[6] you will see that they are equal.
Your assignment in fcn02 of a=b does not work as you intended due to the fundamental concept of passing values to a function. When you call the function fcn02(a) the value "a" (the address of the beginning of the array) is copied to the value of "a" in fcn02. Changing "a" in fcn02 does not change "a" in the calling function.
Example for clarification NOTE( Using the same value "a" can be confusing so I changed it a bit).:
int func02( int* b ) // address of a is copied to b
{
... // some code...c is dynamically allocated and has an address of 0x80004d30
b = c; // b is set to address of c; thus, b address is now 0x80004d30
// a is unchanged and you now have a memory leak since you didn't delete b.
}
int main()
{
int a[5] = {1,2,3,4}; // address is 0x28cc58
func02(a); // complier will make a copy of the value of a to b
// address (i.e. value) of a is still 0x28cc58
}
Memory layout of why you see 5:
int a[5] = {1,2,3,4,5}; // 0x28cc64
int x = 7; // 0x28cc5c
{ array a }{ x }
---- ---- ---- ---- ---- ----
| 1 | 2 | 3 | 4 | 5 | 7 |
---- ---- ---- ---- ---- ----
However to answer you question you can NOT assign one array to another.
int a[5] = {1,2,3,4,5};
int b[5];
b = a;
for ( int i = 0; i<5; ++i )
{
cout << b[i] << endl;
}
The compiler will not allow this.
Here is quick and dirty solution keeping your function parameters the same for guidance:
void e02(){
int a[6] = {15, 9, 8, 4, 3, 0};
int sizeofA = 5;
int numToAdd = 5;
fn02(a, sizeofA, numToAdd);
cout << endl;
for(int i = 0; i < n; i++) {
cout << a[i] << " ";
}
}
void fn02(int* a, int &n, int x) {
n += 1;
int i = 0;
while( i < n ) {
if ( a[i] > x ) {
++i;
}
else {
int tmp = a[i];
a[i] = x;
x = tmp;
}
}
}
Answer from Carlos on Stack OverflowI will provide some concepts that will potentially help you derive a solution to your problem. Then provide a quick solution that can help you with your final solution.
...If I just assign a = b like this then I get the output 15, 9, 8, 4, 3, 5 with 5 being a garbage value.
The output of the number 5 has nothing to do with your assignment of a=b in fcn02. The value 5 is actually the value of x in the calling function. You are accessing the array outside the bounds of it's original allocation thus accessing the value of next address of the size of int. In this case it's the value of x. if you spit out the address of x and the address of a[6] you will see that they are equal.
Your assignment in fcn02 of a=b does not work as you intended due to the fundamental concept of passing values to a function. When you call the function fcn02(a) the value "a" (the address of the beginning of the array) is copied to the value of "a" in fcn02. Changing "a" in fcn02 does not change "a" in the calling function.
Example for clarification NOTE( Using the same value "a" can be confusing so I changed it a bit).:
int func02( int* b ) // address of a is copied to b
{
... // some code...c is dynamically allocated and has an address of 0x80004d30
b = c; // b is set to address of c; thus, b address is now 0x80004d30
// a is unchanged and you now have a memory leak since you didn't delete b.
}
int main()
{
int a[5] = {1,2,3,4}; // address is 0x28cc58
func02(a); // complier will make a copy of the value of a to b
// address (i.e. value) of a is still 0x28cc58
}
Memory layout of why you see 5:
int a[5] = {1,2,3,4,5}; // 0x28cc64
int x = 7; // 0x28cc5c
{ array a }{ x }
---- ---- ---- ---- ---- ----
| 1 | 2 | 3 | 4 | 5 | 7 |
---- ---- ---- ---- ---- ----
However to answer you question you can NOT assign one array to another.
int a[5] = {1,2,3,4,5};
int b[5];
b = a;
for ( int i = 0; i<5; ++i )
{
cout << b[i] << endl;
}
The compiler will not allow this.
Here is quick and dirty solution keeping your function parameters the same for guidance:
void e02(){
int a[6] = {15, 9, 8, 4, 3, 0};
int sizeofA = 5;
int numToAdd = 5;
fn02(a, sizeofA, numToAdd);
cout << endl;
for(int i = 0; i < n; i++) {
cout << a[i] << " ";
}
}
void fn02(int* a, int &n, int x) {
n += 1;
int i = 0;
while( i < n ) {
if ( a[i] > x ) {
++i;
}
else {
int tmp = a[i];
a[i] = x;
x = tmp;
}
}
}
In order to insert an element in a sorted vector (decreasing order), you could try this:
#include <iostream>
#include <vector>
using namespace std;
void InsertItemInSortedArray(std::vector<int>& vec, int item)
{
auto high_pos=std::lower_bound (vec.rbegin(), vec.rend(), item);
vec.insert(high_pos.base(), item);
}
int main() {
std::vector<int> vec = {15, 9, 8, 4, 3};
int item = 5;
InsertItemInSortedArray(vec, item);
for (const auto& elem : vec)
{
std::cout << elem << std::endl;
}
return 0;
}
[Help] Why can't you assign an array to another array?
C array declaration and assignment? - Stack Overflow
Changing array inside function in C - Stack Overflow
pointers - How to reassign value of element of char array in C - Stack Overflow
Videos
What you're doing won't work. You're simply creating a local array and then assigning your local parameter a to the beginning of this array (which changes nothing about the a in main). So the real thing isn't modified.
To actually modify this, you can either do a plain for loop:
// NOTE: this assumes array has the same number of elements as x
void reasi(char** a)
{
char* x[] = {"1","22","333"};
for (unsigned i = 0; i < sizeof x / sizeof *x; ++i)
a[i] = x[i];
}
Or use memcpy:
#include <string.h>
// NOTE: this assumes array has the same number of elements as x
void reasi(char** a)
{
char* x[] = {"1","22","333"};
memcpy(a, x, sizeof x);
}
Your array is not a 2D array. By seeing your code I assume you mistaken 1D array for 2D array, hence I will answer according to it
#include <stdio.h>
#include <stdlib.h>
void reasi(char** a){
a[0] = "1";
a[1] = "22";
a[2] = "333";
}
int main()
{
char* a[] = {"bob","alice","tom"};
reasi(a);
for(int i=0; i< 3; i++)
{
printf("%s\n",a[i]);
}
}
This will give you your desired output.
The following code snippet has an error error: invalid initializer:
int main() {
int a[3] = {0, 1, 2};
int b[3];
b = a;
return 0;
}There were some StackOverflow answers regarding this, but I still have some questions about it.
My Understanding
There is the mantra that "arrays decay into pointers", but I'm aware that does not mean that arrays are equivalent to pointers.
Here,
int main() {
int *p = malloc(3 * sizeof(int));
for (int i = 0; i < 3; i++)
p[i] = i;
}
The compiler will allocate a pointer's worth of memory to p, and the value of p is the address of some location on the heap. In the top code snippet, the compiler allocates 3 ints worth of memory and the value of a is that entire block of memory.
So for me, the above code snippet is similar to declaring an int. When declaring some int i, the compiler allocates an int's worth of memory for i and i's value is that block of memory.
And for an int, this would compile just fine:
int main() {
int x = 5;
int y;
y = x;
return 0;
}
I don't see why the compiler couldn't just take the data stored at a and copy that over to b, just like how it does above.
I also started messing around with the code some more, and I noticed that this worked for some reason:
int main() {
int a[3] = {1, 2, 3};
int *b;
b = a;
return 0;
}What's the difference here?
EDIT: fixed typos
Simply put, arrays are not assignable. They are a "non-modifiable lvalue". This of course begs the question: why? Please refer to this question for more information:
Why does C++ support memberwise assignment of arrays within structs, but not generally?
Arrays are not pointers. x here does refer to an array, though in many circumstances this "decays" (is implicitly converted) to a pointer to its first element. Likewise, y too is the name of an array, not a pointer.
You can do array assignment within structs:
struct data {
int arr[10];
};
struct data x = {/* blah */};
struct data y;
y = x;
But you can't do it directly with arrays. Use memcpy.
int x [sz];
int *y = x;
This compiles and y will be the same as x.
In c you can't pass a variable by reference, the array variable that you assign inside the function contains initially the same address as the passed pointer, but it's a copy of it so modifying it will not alter the passed pointer.
You need to pass the address of the pointer in order to be able to alter it, like this
// Change the pointer of the array
void change(int **array, int length)
{
*array = malloc(length * sizeof(int));
if (*array == NULL)
return;
for (int i = 0 ; i < length ; i++)
(*array)[i] = 1;
}
Then in main() you cannot assign to an array, doing so through this kind of function is surely undefined behavior. The array defined in main() is allocated on the stack and you cannot assign anything to an array since they are non-writeable lvalues so you cannot make it point to a heap memory location obtained with malloc(), you need to pass a pointer like this
int *array;
change(&array, length);
free(array);
If you want the function to replace the previous array, it will have to free() the malloc()ed data (note that passing NULL to free() is well defined), so
// Change the pointer of the array
void change(int **array, int length)
{
free(*array);
*array = malloc(length * sizeof(int));
if (*array == NULL)
return;
for (int i = 0 ; i < length ; i++)
(*array)[i] = 1;
}
then in main()
int *array;
array = NULL;
change(&array, length);
change(&array, length);
change(&array, length);
change(&array, length);
free(array);
will do what you apparently want.
Ok, i will make the answer short.
- Arrays are always passed by reference in C
change(array, length); In this line, it means reference to the first element of the array variable is passed to the function.
Now the function needs a pointer to catch the reference, it can be a pointer or it can be an array. Note that the pointer or the array is local to the function.
You received it in a pointer named array. Which is definitely a pointer but it is not the same as array in main function. It is local to the change function.
You declared a new array dynamically, and assigned a pointer named new with it. And all the changes you did were to new pointer.
Everything is ok till now.
- Now you assigned the new pointer to the array pointer which is local to the change function.
This is the real issue. As even though the array is in heap section, and it will remain in the memory, but the *array and *new are local pointer variables.
Also array pointer in change function is different from array pointer in main function.
The solution to this problem is Manipulate the data of array pointer directly.
void change(int *array,int length) { int i; for(i = 0 ; i < length ; i++) array[i] = 1; }
In this way you are directly overwriting values of array in main function. Everything else is correct.
Summerization: array pointer in change function is local to change function. array in main function is local to main function. Making change function's local array pointer point to array in heap section won't change data in actual array. You changed pointer's position, Not the array's data.
You should use the following:
c[2]='a';
In C and C++ "x" is a type of const char [2]. To specify a character you need to use 'x' that is a type of const char.
Double-quotes create null-terminated strings.
Instead, you want a single-quoted character, which is just a single char value:
c[2]='a'; // Now your string is "apale"
Well, when you do
double s[3]={1,2,3};
That memory is not managed by you, so you can not free it. You can only use free when you allocate memory using malloc or calloc (i.e. dynamically allocated memory). Additionally, you have a memory leak there because
ptr=(double*)malloc(sizeof(double)*3); // here you allocate memory
...
ptr = s; // here you change the pointer address but allocated memory is never freed
a solution would be to use a for loop to copy the values from s to ptr, and do the same in changePtr to copy values from s1 to ptr.
Edit 1
To your original question:
Short answer: Yes, you can reassign a pointer to a smaller array in C.
Long answer: The short answer is misleading. Arrays are also simply pointers in C. And for a better understanding of this concept, you might want to read this thread, especially take a look at this answer.
The problem is that you try to de-allocate the memory on stack.
Whenever you create a local variable, à la int a = 5, it's pushed on the stack, that is this variable gets memory allocated on stack and after the function call (main()) is over the memory is de-allocated - all this happens automatically!
In your case, here is what happens:
// memory is allocated automatically on stack for the local variable "s"
double s[3]={1,2,3};
// assign the stack address of "s" to "ptr"
ptr = s;
// de-allocate the managed stack address of "s", which is NOT allowed!
free(ptr);
Creating dynamic memory, e.g. via malloc, on the other hand happens in the heap memory, which needs to be managed by the programmer, that is allocating (malloc()) and de-allocating (free()) memory is allowed and must be done with great care.
So, in your programm when it hits this line free(ptr);, the assertion fails, because the target memory address doesn't meet the requirement -> IsValidHeapPointer: No ptr is not a valid heap pointer, because it holds the stack address of the s variable at that point. :)
Edit 2
I get garbage values like -1456815990147....1 when I print out the values of ptr after calling changePtr. Why is this?
It's because, you free the memory of ptr in changePtr(ptr) first, that is the content of ptr is written with some "garbage" value.
And then here you allocate new memory and assign it to ptr:
ptr = (double *) malloc(sizeof(double) * 2);
After this point, the changes you make via ptr (i.e. ptr[i] = 12) has no influence on the previous address which ptr held. So, simply remove the free(ptr) and the above line, you don't need them.
Edit 3
So does
ptrnow only contain 2 values, right? After I delete that line you mentioned, and then printed out the values in ptr, it shows the correct values for ptr[0] and ptr[1] and then a garbage value for ptr[2].
Correct. ptr[2] is freed before, so unless you assign a new value to that address, it will remain a garbage. Also be careful after you have freed heap memory. You should not use the pointer to access memory or assign a new value to it. Consider your pointer "void" after you call free on it.
When I tried to print the size of it with printf("%d", sizeof(ptr)), it shows 8 and printf("%d", sizeof(ptr)/sizeof(ptr[0]) shows 1.
ptr is a pointer. sizeof(ptr) returns 8 bytes, that's the size of address that a pointer in your system holds. So, it is not the size of array... Further, determining the size of a pointer (which points to an array and passed to a function as reference - like you did changePtr(ptr)) during the runtime is programmatically not possible, you have to explicitly pass the array size to a function, if you want to do some loop operations.
This should be a valid code as taken from CS50:
// Copy string into memory, including '\0'
for (int i = 0; i <= strlen(s); i++)
{
t[i] = s[i];
}But in other places (for instance https://www.reddit.com/r/C_Programming/comments/14oolus/comment/jqexig6/?utm_source=share&utm_medium=web2x&context=3), I have read that arrays cannot be assigned values this way. Must be missing something for sure.
"I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is reassign a pointer."
"
bshould just point to the address ofa. Why isn't this doable?"
You seem to confuse here something. b isn't a pointer. It is an array of three int elements.
b = a;
Since b is used here as lvalue in the assignment, it is taken as of type int [3], not int *. The pointer to decay rule takes no place in here for b, only for a as rvalue.
You cannot assign an array (here b) by a pointer to the first element of another array (here a) by using b = a; in C.
The syntax doesn't allow that.
That's what the error
"array type 'int [3]' is not assignable"
is saying to you for b.
Also you seem to be under the misunderstanding that the pointer to decay rule means that an array is anyhow converted to a pointer object, which can in any manner store addresses of locations of different objects.
This is not true. This conversion is only happening in a very implicit kind of way and is subject of this SO question:
Is the array to pointer decay changed to a pointer object?
If you want to assign the values from array a to the array b, you can use memcpy():
memcpy(b, a, sizeof(a));
I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is reassign a pointer.
bshould just point to the address ofa. Why isn't this doable?
Because b isn't a pointer. When you declare and allocate a and b, this is what you get:
+---+
| 1 | a[0]
+---+
| 2 | a[1]
+---+
| 3 | a[2]
+---+
...
+---+
| 4 | b[0]
+---+
| 5 | b[1]
+---+
| 6 | b[2]
+---+
No space is set aside for any pointers. There is no pointer object a or b separate from the array elements themselves.
C was derived from an earlier language called B, and in B there was a separate pointer to the first element:
+---+
b: | +-+--+
+---+ |
... |
+----+
|
V
+---+
| | b[0]
+---+
| | b[1]
+---+
...
+---+
| | b[N-1]
+---+
When Dennis Ritchie was developing C, he wanted to keep B's array semantics (specifically, a[i] == *(a + i)), but he didn't want to store that separate pointer anywhere. So instead he created the following rule - unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array, and that value is not an lvalue.
This has several practical effects, the most relevant here being that an array expression may not be the target of an assignment. Array expressions lose their "array-ness" under most circumstances, and simply are not treated like other types.
Edit
Actually, that misstates the case - array expression may not be the target of an assignment because an array expression is not a modifiable lvalue. The decay rule doesn't come into play. But the statement "arrays are not treated like other types" still holds.
End Edit
The upshot is that you cannot copy the contents of one array to the other using just the = operator. You must either use a library function like memcpy or copy each element individually.