int *p[10]={5,663,36,6};
*(p - 1) = 'e';
int c=*(p-1);
printf("%c",c);
i am not able to understand why we use negative number in array index
*(p - 1) = 'e';
For your example it would be undefined behaviour, but there are situations where you might want to use it, notably if your pointer was pointing to somewhere inside an array and you check that you are still inside the bounds of the array.
Like in this example...
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
char hello[]="worlld";
char *p;
for(p=hello;*p!='\0';p++) {
if ((p>hello) && (p[-1]==p[0])) {
printf("%c\n",p[0]);
}
}
return(0);
}
The language does not prevent you from using negative numbers in indexing of an array or a pointer. This does not meant that it is always correct. i.e. in your example it would access an array element which is 1 position before the beginning of the array. in other words you access invalid memory addres.
However in the situation like the following, where p1 points to a non-0 element of the array, you can use negative indexes:
int p[] = {1,2,3,4};
int *p1 = &p[1];
int x = *(p1-1);
int y = p1[-1]; // equivalent to the previous one
In both cases 'x' and 'y' will become '1';
i am not able to understand why we use negative number in array index
That's because
you apparently think [] is an array operator, but it is not. It is a pointer operator, defined in terms of pointer arithmetic, which, in a general sense, permits subtracting integers from pointers.
you seem to have an expectation of some particular kind of behavior arising from evaluating your example code, but it exhibits undefined behavior on account of performing arithmetic on pointer p that does not produce a result pointing into (or just past the end of) the same object that p points [in]to. "Undefined" means exactly what it says. Although an obvious program failure or error message might be emitted, you cannot rely on that, or on any other particular behavior. Of the entire program.
Related
It is said in C that when pointers refer to the same array or one element past the end of that array the arithmetics and comparisons are well defined. Then what about one before the first element of the array? Is it okay so long as I do not dereference it?
Given
int a[10], *p;
p = a;
(1) Is it legal to write --p?
(2) Is it legal to write p-1 in an expression?
(3) If (2) is okay, can I assert that p-1 < a?
There is some practical concern for this. Consider a reverse() function that reverses a C-string that ends with '\0'.
#include <stdio.h>
void reverse(char *p)
{
char *b, t;
b = p;
while (*p != '\0')
p++;
if (p == b) /* Do I really need */
return; /* these two lines? */
for (p--; b < p; b++, p--)
t = *b, *b = *p, *p = t;
}
int main(void)
{
char a[] = "Hello";
reverse(a);
printf("%s\n", a);
return 0;
}
Do I really need to do the check in the code?
Please share your ideas from language-lawyer/practical perspectives, and how you would cope with such situations.
(1) Is it legal to write --p?
It's "legal" as in the C syntax allows it, but it invokes undefined behavior. For the purpose of finding the relevant section in the standard, --p is equivalent to p = p - 1 (except p is only evaluated once). Then:
C17 6.5.6/8
If both the pointer
operand and the result point to elements of the same array object, or one past the last
element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
The evaluation invokes undefined behavior, meaning it doesn't matter if you de-reference the pointer or not - you already invoked undefined behavior.
Furthermore:
C17 6.5.6/9:
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object;
If your code violates a "shall" in the ISO standard, it invokes undefined behavior.
(2) Is it legal to write p-1 in an expression?
Same as (1), undefined behavior.
As for examples of how this could cause problems in practice: imagine that the array is placed at the very beginning of a valid memory page. When you decrement outside that page, there could be a hardware exception or a pointer trap representation. This isn't a completely unlikely scenario for microcontrollers, particularly when they are using segmented memory maps.
The use of that kind of pointer arithmetic is bad coding practice, as it might lead to a significant bunch of hard to debug problems.
I only had to use this kind of thing once in more than 20 years. I was writing a call-back function, but I did not have access to the proper data. The calling function provided a pointer inside a proper array, and I needed the byte just before that pointer.
Considering that I had access to the entire source code, and I verified the behavior several times to prove that I get what I need, and I had it reviewed by other colleagues, I decided it is OK to let it go to production.
The proper solution would have been to change the caller function to return the proper pointer, but that was not feasible, time and money considering (that part of the software was licensed from a third-party).
So, a[-1] is possible, but should be used ONLY with very good care in very particular situations. Otherwise, there is no good reason to do that kind of self-hurting Voodoo ever.
Note: at a proper analysis, in my example, it is obvious that I did not access an element before the beginning of a proper array, but the element before a pointer, which was guaranteed to be inside of the same array.
Referring to the code provided:
it is NOT OK to use p[-1] with reverse(a);;
it is OK(-ish) to use it with reverse(a+1);, because you remain inside the array.
I have the following code and I am confused why is it now working:
#include<stdio.h>
void modif(const int *p)
{
*(p+1)=5;
}
int main()
{
int a=1;
printf("\n%d",a);
modif(&a);
printf("\n%d",a);
return 0;
}
The error I am getting is this one:
main.c: In function 'modif':
main.c:6:9: error: assignment of read-only location '*(p + 4)'
*(p+1)=5;
^
exit status 1
In my opinion the address next to p should be modifiable. I have tried to modify the values at addresses that were further away and the result was the same.
When using "const" keyword before a parameter passed by reference what is the first address that is actually modifiable?
This statement
*(p+1)=5;
is problematic for a couple of reasons.
p is const-qualified. So that's the reason for the error you get.
You violate the promise you made to the compiler (that you wouldn't modify the object pointed to by p).
If you didn't have the const qualifier, it's still wrong.
Because the object that p points to is a single int, so dereferencing p+1 is undefined behaviour.
Note that evaluating p+1 is fine even if p points to a single int object. It's allowed per C11, 6.5.6/9.
But dereferencing it is not valid.
If there's a valid object at p + 1 (provided that object itself is mutable - otherwise, this will be undefined behaviour), you could cast away the const in modif() and legally modify it. For example, the below is valid (but not something I recommend - if you want modif to be able to modify a's contents, it doesn't make sense to qualify p with const here).
#include<stdio.h>
void modif(const int *p)
{
int *q = (int*)p;
*(q+1)=5;
}
int main()
{
int a[2] = {0};
modif(a);
printf("\n%d, %d",a[0], a[1]);
return 0;
}
'In my opinion the address next to p should be modifiable'
Authors of C language have opposite opinion. And it's their opinion which counts.
The C semantics allows you to perform a so-called pointer arithmetics, which includes adding and subtracting integers to/from typed pointers. The pointer value resulting from such operation points to an element of the same array, respective number of items farther or earlier in the array.
However the const modifier applies to the whole array (despite its size being not specified), so it does not vanish in such operation. If it did, you could just do *((p+1)-1) to access a *p variable without the const restriction!
You're just passing a pointer which in C may point to an arbitrarily sized array of objects -- size 1 for a single object is just one possible case. It's your job as a programmer to find means how the function knows how many objects there are.
If the pointer is a pointer to a const, this means the whole array is immutable.
In your code, your pointer only points to a single object, so accessing the non-existing object at index 1 is just undefined behavior. If this object would exist, would you expect it to be modifyable through a const pointer? Of course not ...
Can someone explain why printing the pointers to the two ints results in them being placed in different locations in relation to the chars.
The piece of code below should print out the memory address from &a to &c which (I think) should include the two ints defined but it doesn't, however when I try to find out where they're stored in memory (see second code segment) it does print them between the two chars as expected.
Please explain why printing the int pointers effects the ints being stored between the chars in memory.
The two code samples are the same except code 2 has an extra line printf("\n\n%p,%p\n",&i,&j); which prints the pointers of the two ints.
Edit: Yes I know the prinf formating is ugly but the code was only to help me clarify how memory and pointers work, so I didn't need it to be pretty
Code1
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv){
char a='a';
int i=1;
int j=2;
char c='c';
char *pos;
for ( pos=&c; pos<=&a; pos++ ){
printf("%p\t",pos);
}
printf("\n");
for ( pos=&c; pos<=&a; pos++ ){
printf("%i\t\t",*pos);
}
}
Results from Code1
0x7ffde6321e7e 0x7ffde6321e7f
99 97
Code2
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv){
char a='a';
int i=1;
int j=2;
char c='c';
char *pos;
for ( pos=&c; pos<=&a; pos++ ){
printf("%p\t",pos);
}
printf("\n");
for ( pos=&c; pos<=&a; pos++ ){
printf("%i\t\t",*pos);
}
printf("\n\n%p,%p\n",&i,&j);
}
Results from Code2
0x7ffc3575616b 0x7ffc3575616c 0x7ffc3575616d 0x7ffc3575616e 0x7ffc3575616f 0x7ffc35756170 0x7ffc35756171 0x7ffc35756172 0x7ffc35756173 0x7ffc35756174 0x7ffc35756175 0x7ffc35756176 0x7ffc35756177
99 2 0 0 0 1 0 0 0 -4 127 0 97
0x7ffc35756170,0x7ffc3575616c
You're relying on somethingNote 1 which is not specified in C standard. The behaviour cannot be defined. It invokes undefined behavior.Note 2
That said, you should always cast the argument of %p to void *, as the expected type is void * and there's no default promotion for pointers.
Note 1:
C does not mention or guarantee the order of allocation of variables / objects in a program. There's no guarantee that they will have consecutive memory locations, either increasing or decreasing. They are purely allowed to have random memory locations, so the theory you're believing in,
for ( pos=&c; pos<=&a; pos++ )
does not hold true. An(y) implementation can choose to place (reorder) variable(s) however it does see fit. There's absolutely no guarantee of the order of memory address with respect to their definition in the code.
Note 2:
For relational operators, quoting C11. chapter ยง6.5.8, (emphasis mine)
When two pointers are compared, the result depends on the relative locations in the
address space of the objects pointed to. If two pointers to object types both point to the
same object, or both point one past the last element of the same array object, they
compare equal. If the objects pointed to are members of the same aggregate object,
pointers to structure members declared later compare greater than pointers to members
declared earlier in the structure, and pointers to array elements with larger subscript
values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the
expression P points to an element of an array object and the expression Q points to the
last element of the same array object, the pointer expression Q+1 compares greater than
P. In all other cases, the behavior is undefined.
So, for your case, the comparison pos<=&a; is an attempt to compare two pointers which are neither
pointing to same object
members of the same aggregate object
pointers to array elements
pointers to members of the same union object
In short, they are not within the defined scope and hence, using them as operand of the relational operator invokes undefined behaviour.
The location of local variables is implementation defined. The compiler may put them in any order it deems best.
Making seemingly unrelated code changes such as an extra print statement or changing the optimization level can change how the compiler lays out the variables.
In short, you can't depend on any particular layout of variables in memory.
Local variables are placed in the stack (or in register if possible & if their address is not referred). In your example the i is first and j is second local vars, so you have push i, push j - the address of the second &j is &i-1.
I got this tiny little program down here, that comes with preassigned 'count' number and then parses it to format of 'xxx', where x is a 0 or corresponding cipher (e.g from '6' I got 006 and from 234 I get 234). When I get it like this
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
int count = 0;
char number[2] = {0};
int base0 = count % 10;
int base1 = ((count % 100) - base0) / 10;
int base2 = ((count % 1000) - base1) / 100;
sprintf(number, "%d%d%d", base2, base1, base0); //print into the number variable
printf("%s\n", number);
}
everything is working fine, but if I switch 'number' variable definition with
char* number = NULL;
I get segmentation fault. Why is that? It should just point to the beggining of the string.
In C, a string is represented as an array of characters; the line
char number[2] = { 0 };
therefore defines a two character array ('string') initialised with two null characters.
An array is a series of contiguous (read 'next to each other') blocks of memory that can each be individually accessed via the subscript operator (square brackets).
When you changed the above line to
char* number = NULL;
You are no longer defining a character array. In this case you are now defining a pointer to char variable. Because arrays are basically blocks of memory next to each other, if you know where the first element is, it is possible to then locate any of the others. So since the deference operator allows you to access the value pointed at by a pointer, you can access the ith element in a string with
*(char + i)
which in C is exactly equivalent to
char[i]
Now in your case, you haven't set the char* to point to actual memory containing a real string, you have assigned the NULL pointer, which means 'this pointer points nowhere'. Treating a char* as a string requires it to be dereferenced (following the pointer); however, dereferencing a NULL pointer is an undefined behaviour, which in this situation has caused a seg fault
NULL is a well-defined "nowhere" - it's an invalid pointer value that's guaranteed not to point to a function or an object in memory. When you set number to NULL, you're saying that number isn't pointing anywhere meaningful.
Trying to work through an invalid pointer leads to undefined behavior - in this case, a segfault.
Arrays and pointers are not the same thing. Array expressions will "decay" (be converted) to pointer types in most circumstances, but the object is always an array.
"everything is working fine,"
Wait there. You already have sever shortage of required memory. In case of
sprintf(number, "%d%d%d", base2, base1, base0);
number needs much more memory to stay within the bounds, so as is, your program invokes undefined behavior by accessing out of bound memory. You need to allocate enough memory to hold the final sting to be held by number.
Anyways, NULL is defined to be an invalid memory location, accessing which invoke UB again, so you cannot use it to store anything, at all.
char number[2]; gives you two bytes of memory for number
char * number = null; gives you zero bytes of memory for *number.
When you do sprintf, you are writing three bytes into the number.
When say "char *number = null", you are writing into null, which results in segfault.
When you do sprintf, you are writing 3 bytes into 2 bytes of allocated memory - you are overwriting 1 extra byte into stack.
could someone explain why
int main(int argc, const char * argv[]) {
while (* argv)
puts(* argv++);
return 0 ;
}
is legal, and
int main(int argc, const char * argv[]) {
argv += argc - 1;
while (* argv)
puts(* argv--);
return 0 ;
}
isn't?
In both cases the 'crement inside the while loop will point outside of the bounds of argv. Why is it legal to point to an imaginary higher index, and not to an imaginary lower index?
Best regards.
Because the C standard says you can form a pointer to one past the end of an array, and it will still compare properly to pointers into the array (though you can't dereference it).
The standard does not say anything of the sort for a pointer to an address before the beginning of an array -- even forming such a pointer gives undefined behavior.
Loop semantics and half-open intervals. The idiomatic way for iterating through an array or list of objects pointed to by a pointer is:
for (T *p = array; p < array + count; p++)
Here, p ends up being out-of-bounds (off by one, pointing one past the end of the array), so it's (not only conceptually) useful to require this not to invoke undefined behavior (the Standard actually imposes this requirement).
The standard forces argv[argc] to be equal to NULL, so dereferencing argv when it's been incremented argc times is legal.
On the other hand nothing is defined about the address preceding argv, so argv - 1 could be anything.
Note that argv is the only array of strings guaranteed to behave this way, as far as I know.
From the standard:
5.1.2.2.1 Program Startup
If they are declared, the parameters to the main function shall obey the following costraints:
argv[argc] shall be a null pointer
argv++ or ++argv as it is const pointer.
If you take a simple array like char* arr[10] and try arr++ it will give error