C Pointer to negative length array strange behaviour Apple LLVM compiler - c

I know that negative length arrays have undefined behaviours, but with the standard of E1[E2] being identical to (*((E1)+(E2))) I expected something to work.
So in this instance what I do is I create an array that spans in direction -32, so the accessible indexes I expected to gain are -31 up to 0.
I am using 8bit unsigned chars of 0 to 255 and signed chars of -128 to +127, but this happens with 32bit integers and 64bit integers too.
I use C99's ability to declare arrays of variable length to construct the negative spanning array, specifically I am compiling to the GNU99 C standards.
I assign these values to the indexes and print them out as I go, all seems to work fine.
It goes strange when I make a pointer to the value at array index [-31] and then loop through that, 0 to 31, printing the values.
const signed char length = 32;
const signed char negativeLength = -length;
signed char array[negativeLength];
for ( signed char ii = 0; ii > negativeLength; ii-- ) {
array[ii] = ii;
printf( "array %d\n", array[ii] ); /* Prints out expected values */
}
printf( "==========\n" );
signed char * const pointer = &array[negativeLength + 1];
for ( unsigned char ii = 0; ii < length; ii++ ) {
printf( "pointer %d\n", pointer[ii] ); /* Begins printing expected values then goes funky */
}
I get different results every time, but with 32 it generally starts out okay for the first 3 values, it then goes funky and starts printing out -93 up to +47 and then at index pointer[8], array[-23] it goes fine again.
I am running this on an iPad 2.
What exactly is going on here? Is the iPad messing with the pointer or the array when it detects the negative spanning array length?

I sometimes advocate understanding the behavior observed in some C implementations in situations where the C standard does not define the behavior, because it can be illuminating about how certain implementing work or how computers work. In this case, however: Do not do that.
To access an array with arbitrary integer indices, from X (inclusive) to Y (exclusive), do this:
ElementType ArrayMemory[Y-X], *Array = ArrayMemory - X;
If X <= 0 <= Y and X < Y, the behavior of this is defined by the C standard.

Why would you expect something to work when you've done something with undefined behaviour?
While E1[E2] being equivalent to *(E1 + E2) is well defined, the data you're accessing is not well defined so all bets are off.

Related

Why does a high-value input prevent an array from using the actual input value in C?

I'm making a function that takes a value using scanf_s and converts that into a binary value. The function works perfectly... until I put in a really high value.
I'm also doing this on VS 2019 in x64 in C
And in case it matters, I'm using
main(int argc, char* argv[])
for the main function.
Since I'm not sure what on earth is happening, here's the whole code I guess.
BinaryGet()
{
// Declaring lots of stuff
int x, y, z, d, b, c;
int counter = 0;
int doubler = 1;
int getb;
int binarray[2000] = { 0 };
// I only have to change things to 1 now, am't I smart?
int binappend[2000] = { 0 };
// Get number
printf("Gimme a number\n");
scanf_s("%d", &getb);
// Because why not
printf("\n");
// Get the amount of binary places to be used (how many times getb divides by 2)
x = getb;
while (x > 1)
{
d = x;
counter += 1;
// Tried x /= 2, gave me infinity loop ;(
x = d / 2;
}
// Fill the array with binary values (i.e. 1, 2, 4, 8, 16, 32, etc)
for (b = 1; b <= counter; b++)
{
binarray[b] = doubler * 2;
doubler *= 2;
}
// Compare the value of getb to binary values, subtract and repeat until getb = 0)
c = getb;
for (y = counter; c >= 1; y--)
{
// Printing c at each subtraction
printf("\n%d\n", c);
// If the value of c (a temp variable) compares right to the binary value, subtract that binary value
// and put a 1 in that spot in binappend, the 1 and 0 list
if (c >= binarray[y])
{
c -= binarray[y];
binappend[y] += 1;
}
// Prevents buffer under? runs
if (y <= 0)
{
break;
}
}
// Print the result
for (z = 0; z <= counter; z++)
{
printf("%d", binappend[z]);
}
}
The problem is that when I put in the value 999999999999999999 (18 digits) it just prints 0 once and ends the function. The value of the digits doesn't matter though, 18 ones will have the same result.
However, when I put in 17 digits, it gives me this:
99999999999999999
// This is the input value after each subtraction
1569325055
495583231
495583231
227147775
92930047
25821183
25821183
9043967
655359
655359
655359
655359
131071
131071
131071
65535
32767
16383
8191
4095
2047
1023
511
255
127
63
31
15
7
3
1
// This is the binary
1111111111111111100100011011101
The binary value it gives me is 31 digits. I thought that it was weird that at 32, a convenient number, it gimps out, so I put in the value of the 32nd binary place minus 1 (2,147,483,647) and it worked. But adding 1 to that gives me 0.
Changing the type of array (unsigned int and long) didn't change this. Neither did changing the value in the brackets of the arrays. I tried searching to see if it's a limit of scanf_s, but found nothing.
I know for sure (I think) it's not the arrays, but probably something dumb I'm doing with the function. Can anyone help please? I'll give you a long-distance high five.
The problem is indeed related to the power-of-two size of the number you've noticed, but it's in this call:
scanf_s("%d", &getb);
The %d argument means it is reading into a signed integer, which on your platform is probably 32 bits, and since it's signed it means it can go up to 2³¹-1 in the positive direction.
The conversion specifiers used by scanf() and related functions can accept larger sizes of data types though. For example %ld will accept a long int, and %lld will accept a long long int. Check the data type sizes for your platform, because a long int and an int might actually be the same size (32 bits) eg. on Windows.
So if you use %lld instead, you should be able to read larger numbers, up to the range of a long long int, but make sure you change the target (getb) to match! Also if you're not interested in negative numbers, let the type system help you out and use an unsigned type: %llu for an unsigned long long.
Some details:
If scanf or its friends fail, the value in getb is indeterminate ie. uninitialised, and reading from it is undefined behaviour (UB). UB is an extremely common source of bugs in C, and you want to avoid it. Make sure your code only reads from getb if scanf tells you it worked.
In fact, in general it is not possible to avoid UB with scanf unless you're in complete control of the input (eg. you wrote it out previously with some other, bug free, software). While you can check the return value of scanf and related functions (it will return the number of fields it converts), its behaviour is undefined if, say, a field is too large to fit into the data type you have for it.
There's a lot more detail on scanf etc. here.
To avoid problems with not knowing what size an int is, or if a long int is different on this platform or that, there is also the header stdint.h which defines integer types of a specific width eg. int64_t. These also have macros for use with scanf() like SCNd64. These are available from C99 onwards, but note that Windows' support of C99 in its compilers is incomplete and may not include this.
Don't be so hard on yourself, you're not dumb, C is a hard language to master and doesn't follow modern idioms that have developed since it was first designed.

Iterating an array backward in C using an unsigned index

Is the following code, safe to iterate an array backward?
for (size_t s = array_size - 1; s != -1; s--)
array[s] = <do something>;
Note that I'm comparing s, which is unsigned, against -1;
Is there a better way?
This code is surprisingly tricky. If my reading of the C standard is correct, then your code is safe if size_t is at least as big as int. This is normally the case because size_t is usually implemented as something like unsigned long int.
In this case -1 is converted to size_t (the type of s). -1 can't be represented by an unsigned type, so we apply modulo arithmetic to bring it in range. This gives us SIZE_MAX (the largest possible value of type size_t). Similarly, decrementing s when it is 0 is done modulo SIZE_MAX+1, which also results in SIZE_MAX. Therefore your loop ends exactly where you want it to end, after processing the s = 0 case.
On the other hand, if size_t were something like unsigned short (and int bigger than short), then int could represent all possible size_t values and s would be converted to int. In other words, the comparison would be done as (int)SIZE_MAX != -1, which would always return false, thus breaking your code. But I've never seen a system where this could happen.
You can avoid any potential problems by using SIZE_MAX (which is provided by <stdint.h>) instead of -1:
for (size_t s = array_size - 1; s != SIZE_MAX; s--)
...
But my favorite solution is this:
for (size_t s = array_size; s--; )
...
Well, s will never be -1, so your ending condition will never happen. s will go from 0 to SIZE_MAX, at which point your program will probably segfault from a memory access error. The better solution would be to start at the max size, and subtract one from everywhere you use it:
for (size_t s = array_size; s > 0; s--)
array[s-1] = <do something>;
Or you can combine this functionality into the for loop's syntax:
for (size_t s = array_size; s--;)
array[s] = <do something>;
Which will subtract one before going into the loop, but checks for s == 0 before subtracting 1.
IMO in the iterations use large enough signed value. It ss easier to read by humans.

How to pass a variable value to an array in C

I am a novice programmer trying to understand arrays in C. Specifically I want to take the numeric value of a variable and feed it into an array. I tried to assign the value to the array, but failed with error messages. Can someone explain, simplistically, how to push a value into an array and then be able to just access the last digit?
My last attempt:
#include <stdio.h>
unsigned int TMR0 = 158;
int main(void)
{
unsigned int V = TMR0;
unsigned int Random[2] = {V};
printf("%d \n" , *(Random+2));
return 0;
Thanks.
unsigned int Random[2];
Array will be declared with two positions.
Random[0] Random[1] // two accessible positions in that array.
When you are assigning the value to the array,
unsigned int Random[2] = { V} ;
Value will be stored in the first position of array. Random[0].
*(Random+2) will access the position Random[2]. Which is not accessible position for this array. It will lead to undefined behaviour.
Another thing is if you need to assign the values to both the position you have to do like this.
unsigned int Random[2] = {V,V} ;
To access the last element in your array,
*(Random+1) or Random[1]
May this link will help.
You don't actually need an array to access digits of your number -- you just need math.
It's important to realise that "digit" implies a particular numeric base. In the computer, numbers are represented in binary. For convenience, they can be represented in our code using common bases: decimal, hexadecimal, and octal are the ones we generally use in languages like C.
So, to get the last digit in base 10, you would take the value modulo 10:
int val = 158;
int last_digit = val % 10;
printf( "%d\n", last_digit );
If you need to find digits other than the last, you can first perform integer division and then modulo:
int second_to_last_digit = (val / 10U) % 10;
Alternatively you can convert the number into a string, and then look at each character in that string. But I'm not going to go into that here, since it can be confusing to provide too much information to new programmers.

Counter in C Language

I'm mainly an electronics hardware guy, but I've learned the basics of D from a friend, so I decided I'd pick up a more standard language like C. So, any advice would be great.
Basically, I'm using the integer 'phew' as a counter, to reverse all numbers. Super basic, but I'm having trouble finding the way to do this in C. My code:
#include <stdio.h>
int main()
{
int input;
int phew;
printf("Binary Number: ");
scanf("%d", &input);
while(phew < sizeof(input))
{
if(input[phew] == 0)
printf("1");
else
printf("0");
phew++;
}
return 0;
}
And the compiler error was:
helloworld.c: In function ‘main’:
helloworld.c:11:11: error: subscripted value is neither array nor pointer nor vector
if(input[phew] == 0)
^
First of all, in the below statement,
while(phew < sizeof(input))
invokes undefined behavior as phew is an automatic local variable and not initialized. You need to initialize phew like int phew = 0;
In this scenario, sizeof(input) is valid, but does not make any sense.
That said, you can only use the [] operator on an array type. In your case, input is an int, so you are not allowed to write input[n].
to elaboate, quoting the C11 standard, chapter §6.5.2.1
Syntax
postfix-expression [ expression ]
and the description
One of the expressions shall have type pointer to complete object type, the other
expression shall have integer type, and the result has type type.
So, clearly, in your case input is not a "pointer-to-type", hence the error.
To solve the issues,
You can change the type of input as char input[32] = {0};
change the scan statement as `scanf("%29s", input);
add while(phew < strlen(input))
to make sense. You'll be needing string.h header file for that. Check details about strlen() here.
You have to change it like
while(phew < strlen(input) )
{
if(input[phew] == '0') //ASCII 48, decimal
printf("1");
else
printf("0");
phew++;
}
You cannot use [] to get bits of an integer in C; that operator only works on pointer values and an int is not a pointer. You may be familiar with Verilog, where bit vectors and integers are the same thing; but C doesn't have a syntax for accessing bits of an object and [] is only for accessing members of an array.
One correct way to do this is using a bit mask. For example:
for (size_t i = 0; i < (sizeof input)*CHAR_BIT; i++) {
unsigned mask = 1 << i;
if (input & mask) {
putchar('1');
} else {
putchar('0');
}
}
putchar('\n');
What this code does on each iteration of the loop is create an unsigned integer mask by shifting the number 1 into the ith place of the integer. Then mask is bitwise-ANDed with input to give a value that is 0 if that bit is 0 in input (and otherwise some nonzero value equivalent to the place value of the bit). Don't forget to print out a newline at the end or the output may not be visible.
I'm using unsigned arithmetic here because << can have implementation-defined or undefined behavior on signed numbers in C. input can be a regular (signed) int because it will be promoted to unsigned by the & operator.
Also notice that I had to multiply sizeof input by CHAR_BIT (which is defined in <limits.h>) to get the number of bits; sizeof always measures sizes in bytes.
Also see this C FAQ (20.7) about bit manipulations.

post decrement in while conditon in C

I've done a search and I’ve found nothing relevant to my query.
I am currently debugging a C optimizer and the code in question looks like this:
while( x-- )
array[x] = NULL;
What should happen in this instance? And should the result of this logic be consistent across all compilers?
Lets say that the initial value of x in this case is 5.
The problem is that the program crashes, my understanding is that it is caused by a negative array element reference.
Any help would be appreciated.
This cycle will end with x equal to -1 (assuming x is signed), but its body will not produce access to array[-1] at the last step. The last array access is to array[0]. The behavior is consistent across all implementations.
In other words, there's no problem with negative index array access in the code you quoted. But if you attempt to access array[x] immediately after the cycle, then you'll indeed access array[-1].
The code you quoted is a variation of a fairly well-known implementational pattern used when one needs to iterate backwards over an array using an unsigned variable as an index. For example
unsigned x;
int a[5];
for (x = 5; x-- > 0; )
a[x] = 0;
Sometimes less-experienced programmers have trouble using unsigned indices when iterating backwards over an array. (Since unsigned variables never have negative values, a naive implementation of the cycle termination condition as x >= 0 does not work.) This approach - i.e. post-increment in the cycle termination condition - is what works in such cases. (Of course, it works with signed indices as well).
If the initial value of x is 5, it will execute:
array[4] = NULL;
array[3] = NULL;
array[2] = NULL;
array[1] = NULL;
array[0] = NULL;
If x is a signed type, then the final value of x will be -1; otherwise, it will be the maximum value of the type.
Make sure x is non negative before processing the while loop(precondition).
Also x value will be -1 when the process leaves the while loop(post condition). Therefore, after leaving while loop, you should not access the array using x as index.

Resources