I was working through exercises in C++ Primer and found online solutions for Exercise 2.32.
I understood that the following code was illegal because initializing can't convert from int to int*:
int null = 0, *p = null;
However, two of the solutions that were mentioned, that I did not come up with were:
const int null3 = 0, *p3 = null3;
constexpr int null4 = 0, *p4 = null4;
How come it allows these during compile without error? I was still expecting the initialize of p3 and p4 to require the & to denote address (&null3, &null4).
Here is the code I have from my notepad file:
#include <iostream>
int main()
{
// int null = 0, *p = null; // it is not legal; depending on intent there are two ways to fix (that I can think off atm)
{
int null = 0, *p = &null; // if the goal is to point to 'null'
}
{
int null2 = 0, *p2 = 0; // if the goal is to create a nullptr
}
{
const int null3 = 0, *p3 = null3; // if the goal is to create a nullptr
}
{
constexpr int null4 = 0, *p4 = null4; // if the goal is to create a nullptr
}
return 0;
}
When I run via Microsoft Visual Studio CMDPrompt it allows me to 'cl "Exercise 2.32.cpp"' without error.
0 is one way of denoting a null pointer constant. (It's an integer type that evaluates to zero.) In other words it is a special case and you are allowed to assign a pointer type to it.
A standards compliant compiler should issue a diagnostic for the assignments of a pointer type to null3 and null4. (It should also issue a diagnostic for int *p = +0;.) If yours doesn't then check appropriate compiler flags are set.
Using nullptr is far better though:
int *p = nullptr;
Related
I've still getting an error of how the stack around newRow is tried using strncat() so that I can say how many new charters that where added to the string, but in the end I still have a corruption around newRow.
In terms of a variables being passed into this function, I think they are pretty straight forward. I also use sizeOfString as a custom made function because I'm not allowed to use the standard sizeof function.
char* makeRow(char elementOne[20], int elementNumber, int numCycles, int orginalData[40], float ctValues[7]){
char newRow[] = "";
int lookingAt;
int dataPoint;
char* elementPtr;
int charArrSize;
elementNumber = elementNumber--;
elementPtr = elementOne;
int lenOfElemnt = *(&elementOne + 1) - elementOne;
//charArrSize = sizeOfString(elementPtr);
charArrSize = sizeOfString(elementOne);
strncat(newRow, elementOne, charArrSize);
//strcpy(csvThirdRow, (",%s", elementOne));
for (int i = 1; i <= 5; i++)
{
lookingAt = (((i - 1) * 5) + 1 - 1);
int maxLookingAt = numCycles * 5;
dataPoint = orginalData[lookingAt];
char dataPointBuffer[100];
if (lookingAt < maxLookingAt)
{
sprintf(dataPointBuffer, ",%d", dataPoint);
charArrSize = sizeOfString(dataPointBuffer);
strncat(newRow, dataPointBuffer, charArrSize);
}
else
{
strncat(newRow, ",",1);
}
}
char ctBuffer[20];
float ctNumber = ctValues[elementNumber];
sprintf(ctBuffer, ",%.2f\n", ctNumber);
charArrSize = sizeOfString(ctBuffer);
strncat(newRow, ctBuffer, charArrSize);
return newRow;
}
If we omit the array dimension, compiler computes it for us based on the size of initialiser.
So, this
char newRow[] = "";
is same as this
char newRow[1] = "";
The size of newRow array is 1.
You are trying to copy more than 1 character to newRow array which is leading to undefined behaviour and resulting in corruption.
From strncat():
The behavior is undefined if the destination array does not have enough space for the contents of both dest and the first count characters of src, plus the terminating null character....
May you should try giving enough size to newRow array, like this
char newRow[1024] = {0};
There is another problem in your code -
You are returning the address of local variable newRow1) from makeRow() function. Note that a local(automatic) non-static variable lifetime is limited to its scope i.e. the block in which it has been declared. Any attempt to access it outside of its lifetime lead to undefined behaviour.
Couple of things that you can do to fix it:
Either make numRow array static or declare numRow as char * type and allocate memory dynamically to it and, in this case, make sure to free it once done with it.
1). An expression that has type array of type is converted to an expression with type pointer to type that points to the initial element of the array object [there are few exceptions to this rule].
Looks like having a local array in your function prevents tail-call optimization on it on all compilers I've checked it on:
int foo(int*);
int tco_test() {
// int arr[5]={1, 2, 3, 4, 5}; // <-- variant 1
// int* arr = new int[5]; // <-- variant 2
int x = foo(arr);
return x > 0 ? tco_test() : x;
}
When variant 1 is active, there is a true call to tco_test() in the end (gcc tries to do some unrolling before, but it still calls the function in the end). Variant 2 does TCO as expected.
Is there something in local arrays which make it impossible to optimize tail calls?
If the compiler sill performed TCO, then all of the external foo(arr) calls would receive the same pointer. That's a visible semantics change, and thus no longer a pure optimization.
The fact that the local variable in question is an array is probably a red herring here; it is its visibility to the outside via a pointer that is important.
Consider this program:
#include <stdio.h>
int *valptr[7], **curptr = valptr, **endptr = valptr + 7;
void reset(void)
{
curptr = valptr;
}
int record(int *ptr)
{
if (curptr >= endptr)
return 1;
*curptr++ = ptr;
return 0;
}
int tally(void)
{
int **pp;
int count = 0;
for (pp = valptr; pp < curptr; pp++)
count += **pp;
return count;
}
int tail_function(int x)
{
return record(&x) ? tally() : tail_function(x + 1);
}
int main(void)
{
printf("tail_function(0) = %d\n", tail_function(0));
return 0;
}
As the tail_function recurses, which it does via a tail call, the record function records the addresses of different instances of the local variable x. When it runs out of room, it returns 1, and that triggers tail_function to call tally and return. tally sweeps through the recorded memory locations and adds their values.
If tally were subject to TCO, then there would just be one instance of x. Effectively, it would be this:
int tail_function(int x)
{
tail:
if (record(&x))
return tally();
x = x + 1;
goto tail;
}
And so now, record is recording the same location over and over again, causing tally to calculate an incorrect value instead of the expected 21.
The logic of record and tally depends on x being actually instantiated on each activation of the scope, and that outer activations of the scope have a lifetime which endures until the inner ones terminate. That requirement precludes tail_function from recursing in constant space; it must allocate separate x instances.
I'm having a weird behaviour with my C++ code. Here it is.
OI_Id * Reqlist = 0;
int * Idlist = 0;
int Reqsize = listcount; // we calculate listcount somehow earlier.
Idlist = new int [Reqsize];
if (Idlist == 0)
{
return;
}
printf ("Idlist = %0x",Idlist);
Reqlist = new OI_Id [Reqsize]; // OI_Id is a 3rd party lib simple struct.
if (Reqlist == 0)
{
return;
}
printf ("Reqlist = %0x",Reqlist);
So the problem is that in both cases it prints the same value - the same pointer is returned by the new operator. BUT! If we change the length of second allocated array to another value (Reqsize+ 1, for example), everything is OK.
Did anybody meet any similar behaviour? I have no idea what's the reason of the problem.
How do I cast or convert an int* into an int[x]?
First, I know that pointers can be indexed. So I know that I can loop through the pointer and array and manually convert the pointer. (eg. a for loop with arr[i] = p[i]). I want to know if the same result can be achieved in fewer lines of code.
As an example I tried to cast pointer int* c = new int[x] to an array int b[2]
int a = 1;
int b[2] = { 2, 3 };
int* c = new int[b[1]];
c[0] = b[0];
c[1] = b[1];
c[2] = a;
I wanted to see what values were where, so I made a simple program to output addresses and values. The output is just below:
Address of {type: int} &a = 0031FEF4; a = 1
Address of {type: int[2]} &b = 0031FEE4; b = 0031FEE4
Address of {type: int[2]} &b[0] = 0031FEE4; b[0] = 2
Address of {type: int[2]} &b[1] = 0031FEE8; b[1] = 3
Address of {type: int*} &c = 0031FED8; c = 008428C8
Address of {type: int*} &c[0] = 008428C8; c[0] = 2
Address of {type: int*} &c[2] = 008428D0; c[2] = 1
Once I made sure I knew what was where I tried a few things. The first idea that came to mind was to get the address of the second element to the pointer's allocation, then replace the array's memory address with it (see the code just below). Everything I did try ultimately failed, usually with syntax errors.
This is what I tried. I really want this to work, since it would be the simplest solution.
b = &c[1];
This did not work obviously.
Edit: Solution:
Don't do it!
If it's necessary create a pointer to an array and then point to the array; this is pointless for any purposes I can fathom.
For more detailed information see the answer by rodrigo below.
First of all b is an array, not a pointer, so it is not assignable.
Also, you cannot cast anything to an array type. You can, however, cast to pointer-to-array.
Note that in C and C++ pointer-to-arrays are rather uncommon. It is almost always better to use plain pointers, or pointer-to-pointers and avoid pointer-to-arrays.
Anyway, what you ask can be done, more or less:
int (*c)[2] = (int(*)[2])new int[2];
But a typedef will make it easier:
typedef int ai[2];
ai *c = (ai*)new int[2];
And to be safe, the delete should be done using the original type:
delete [](int*)c;
Which is nice if you do it just for fun. For real life, it is usually better to use std::vector.
Though you can't reassign an array identifier.. sometimes the spirit of what you're doing allows you to simply create a reference and masquerade yourself as an array. Note: this is just a slight extension of rodrigo's answer... and it is still worth mentioning that there is probably a better way to accomplish whatever the task is.
#include <iostream>
int main() {
int x[1000] = {0};
for(int i = 0; i < 10; ++i) {
int (&sub_x)[100] = *(int(*)[100])(&x[i*100]);
//going right to left basically:
// 1. x[i*100] -- we take an element of x
// 2. &x[N] -- we take the address
// 3. (int(*)[100]) -- we cast it to a pointer to int[100]
// 4. *(...) -- lastly we dereference the pointer to get an lvalue
// 5. int (&sub_x)[100] -- we create the reference `sub_x` of type int[100]
for(int j = 0; j < 100; ++j) {
sub_x[j] = (i*100)+j;
}
}
for(int i = 0; i < 1000; ++i) {
if(i != 0) {
std::cout << ", ";
}
std::cout << x[i];
}
std::cout << std::endl;
}
As you'd expect the output just ends up printing 0-999 with no gaps
output:
0, 1, 2, ..., 999
I wrote a little test to check for null pointer, I simplified it with int and 0, 1, instead of real classes, what I'm trying to test is something like this: return p ? 1 : 0;
which in real world would be return p ? p->callmethod() : 0;
bool TestTrueFalse();
void main()
{
int i = TestTrueFalse();
}
bool TestTrueFalse()
{
int one = 1;
int * p =&one;
*p = 0;
return p ? 1 : 0;
}
now, you can see, that once the pointer becomes 0 again, the test fails, why?
what's wrong with this? what's the solution?
*p = 0;
you probably meant
p = 0;
*p = 0 sets what the pointer points to, not the pointer
When testing a pointer value with a conditional in C++, it will return true if the value is non-zero and false if the value is 0. In your sample p is slated to point at the local one and hence has a non-zero address (even though the value at the address is 0). Hence you get true
A null pointer is a pointer which points to the address 0, not the value 0.
To set a pointer to null, do:
p = 0;
To elaborate, your code sets the pointed-to-int to 0. For example:
int i = 1;
int *p = &i;
assert(*p == 1); //p points to 1
*p = 0;
assert(*p == 0 && i == 0); //p points to the same location, but that location now contains 0
The code *p = 0; does not set the pointer to null. It sets what p is pointing to zero.
A pointer is an address in memory. int *p = &one; takes the address of the variable one, and stores it in p. *p = 0; stores 0 in the memory pointed to by p, meaning that the value of one is now 0. So, you have changed what p points to, but not p itself. TestTrueFalse() will return 1.
to test it for a null pointer before inspecting the value pointed to you might use code like
if(ip != NULL)
taken from http://www.eskimo.com/~scs/cclass/notes/sx10d.html
NULL might be safer in your code, as it is more compiler independent than just writing 0. and it might also be more clear for others to read in your code.