#include <stdio.h>
int f( int *x ) {
*x = 35;
}
int main( int argc, char *argv[] ) {
int p[32];
int *q = p + 5;
f( q );
printf( "%d", p[5] );
return 0;
}
Can you please explain why the output is 35?
I tried to output the value of p by using printf("%d", p) and right after int p[32], it returned a -2077686688.
I think it just simply because I didn't assign any value to the p[32] array yet, so it just returned a random number.
However, the part that confuses me the most is *q = p + 5
How can an array do that?
Since there is no value in the p array, how can it just return its size in this expression?
In your code, int p[32] sets aside an array of size 32 that can be referenced using p. When you define q to be p + 5, you are assigning q to be a pointer to the 6th (1-indexed) element in memory starting from wherever p points to.
When you pass q to f(), the value at q is set to 35 from whatever was there before (uninitialized memory). Since q points to the same location as p[5], p[5] will be 35 since that is the value set at the location in memory by f().
C is a low-level programming language and the behavior around using memory through C variables might be a bit confusing to programmers coming from languages with higher level abstractions.
Let's break down your main function first.
int p[32];
When a function is called in your program, it gets allocated some section in RAM assigned to your process. This section is called the stack. With this statement, you're telling the compiler that your function (main) needs space for 32 integers in stack. Further statements you make with the variable p will be operating on this space reserved for the 32 integers.
Note that, you're not telling anything to the compiler on how this portion of memory assigned for p is initialized. So all these bytes allocated for 32 integers will store whatever they contained before your function is called.
Let's look at the next one.
int *q = p + 5;
This is very similar but now you are asking for some memory in stack with a size that can fit "a pointer to a integer". Pointer is the C abstraction for bare "memory address with a type". So this space will be used to store addresses in memory, and these addresses will refer to another space in RAM that is intended to store integers.
You are also telling the compiler to initialize the stack space for q, with the value of p + 5. Unlike the space for the 32 integers above (p), the space for q will be initialized right after your function is called.
The expression p + 5 is applying what is called "pointer arithmetic". This is used to take an address in RAM, and go up or down based on whatever offset we need. Remember, p was an array and arrays in C work like pointers (addresses) when they take part in pointer arithmetic. Thus, what p + 5 really means is the "address that is 5 integers after the first address p points to". This ends up being the "pointer to the sixth element of p" (first being p[0]), in other words, the address of p[5].
f(q);
In this statement, you are passing the address stored in q, which happened to be the address of the sixth element in p. The function f in return assigns 35 to the location in RAM pointed by this address, hence changing the integer that would be accessed by p[5] to the integer value of 35.
Right at this point, p[5] is the only element within p that has an initialized value. All other integers in p will continue to store what they held before main was called during the initialization of your program.
printf( "%d", p[5] );
When the execution returns back to main, the integer that can be accessed by p[5] is now set to 35, and that is exactly what you expect to see with this printf statement.
int main() {
int p[32] = { 0 };
// initializing array with zeros; no mode random values in array!
int *q = p + 5;
if (&p == &p[0] && &3[p] == &p[3]) {
printf("Sick sad C world\n");
}
/* We can say that there's no such thing as 'array' in C!
* (actually, C has arrays)
* but C arrays are 'thin layer'; try to compare JS Array and C Arrays
* See this: https://stackoverflow.com/a/381549/10972945
* So: p[0] == *(p + 0) == *p
* 'Array' is an address of it's zero element! */
printf(
"p located at %p\n"
"p + 1 located at %p\n"
"p + 5 located at %p\n"
"Size of int (in bytes) is %zu\n",
(void*) p,
(void*) (p + 1),
(void*) (p + 5),
sizeof(int)
);
/* Try to run this code and substract addresses, one from another.
p located at 0x7ffee3e04750
p + 1 located at 0x7ffee3e04754
p + 5 located at 0x7ffee3e04764
Size of int (in bytes) is 4
See:
address of (p + 1) - address of p
== 0x7ffee3e04754 - 0x7ffee3e04750
== 4 == sizeof(int)
address(p + 5) - address(p)
== 0x7ffee3e04764 - 0x7ffee3e04750
== 0x14 == 20 == 5 * sizeof(int)
*/
}
Related
Arrays in C are actually constant pointers. The pointer to the first element of an array is a constant. Therefore it seems impossible to assign an address value to the array pointer pointer pointing the firs element of the array.
But in some situations it might be useful to have two arrays point to the same location in memory.
So how can I make two arrays point to the same location in such fashion :
int a[10];
int b[10];
a = b; // Not possible
What is below seems to be a valid solution. But, are there alternatives?
int *a;
int *b;
int c[10];
a = c; // If you change the value "a" points to
b = c; // it will be observed on "b"
a[2] = 5;
printf("Output is %d", b[2]);
>> Output is 5
Arrays behave like pointers to their first element, but you can't reassign them:
int a[] = { 1, 2 };
int b[] = { 3, 4 };
b = a; // compilation error: b is constant
The reason is their address, being known at compile time, is stored in a read-only segment of the program, and writing in a read-only segment would be a segmentation fault.
A pointer is a type which contains an address, it can be assigned at runtime.
If you don't know at compile-time how much memory you need, you can ask some to your system with dynamic allocation:
int * integers = malloc(sizeof(int) * 3); // dynamic array of size 3
// or
int * integers = malloc(sizeof(* integers) * 3);
If you want 2 arrays to point to the same memory:
char * interval1 = malloc(sizeof(char) * 2); // sizeof() useless here, char is defined as 1 byte
interval1[0] = 'A'; // equivalent to *(p + 0) = 'A'
interval1[1] = 'Z'; // equivalent to *(p + 1) = 'Z'
char * interval2 = interval1;
But the interest is rather limited if both variables are in the same function.
I didn't add checks, but you should always check for NULL after allocation, and free() when you don't need the memory anymore.
TDLR: if you need to reassign an address, don't use array-type, but pointer-type, it's made to be dynamic.
My question needs some explaination :
First, let's consider a 1D array of size n (dynamic or static). Let's call it tab.
We will simplify by assuming the array is stored in memory from address 0x01 to (0x01 + n - 1).
Now consider a pointer called p. And a starting index i, between 0 and n - 1.
Then we do that :
p = &tab[i];
p has know the value of the address 0x0i. (The notation isn't correct, but you get the point).
Can we read tab[i - 1] or tab[i + 1] using p like this ?
int iprev = *(p - 1);
int inext = *(p + 1);
Or simply like this ?
int iprev = p[-1];
int inext = p[1];
And eventually doing this ?
p--;
p++;
And if that is possible for 1D arrays, can it be for multi-dimensions arrays? And how to implement it in C?
As long as p + i (for any i, positive or negative) doesn't go out of bounds in any direction (i.e., it doesn't point to before tab[0] or after tab[n - 1] in your example) then it's okay.
And remember that for any pointer or array p and index i, the expression *(p + i) is exactly equal to p[i].
To be more precise, it's okay to have a pointer to anywhere, as long as it's pointing to valid memory when you dereference the pointer.
Example:
int tab[N]; // Exact value of N is irrelevant
int *p = tab; // Equal to p = &tab[0]
p--; // After this, p will be pointing out of bounds, this is okay
// Comparing pointers is okay
if (p < tab)
{
/* ... */
}
printf("Value of *p = %d\n", *p); // ERROR: Here you dereference the ouf-of-bounds pointer
I want to get numbers from the keyboard (or from a file: ./a.out < file) and store them in an array. The idea is that the length of the array is unknown.
#include <stdio.h>
#include <stdlib.h>
int* newElem(){
int* elm= malloc(sizeof(int));
if (elm == NULL) {
printf("\nError: memory allocation failed.\n");
exit(-1);
}
return elm;
}
int main(){
int *array,x,size,i=0;
while( scanf("%d",&x)==1 ){
array= newElem();
array[i]=x;
i++;
}
size=i;
free(array);
printf("size=%d",size);
return(0);
}
Why does this crash after I enter:
1 2 3 4 5 6 7 8
In your code
array= newElem();
is going to overwrite the existing pointer (memory) every time. so, array[i] becomes invalid, which essentially is an access out of bounds which in turn invokes undefined behavior. You need to use realloc() to re-size the allocated memory.
Simple.
array= newElem();
array[i]=x;
i++;
newElem() always return int[1] and you tried to access [n]
First you need to know that an array is a sequence of consecutive addresses.
This means that if the address of the first element is 0, the address of the second element will be 1, and the next 2, so on...
When you say x[10] in C, you are in fact saying *(x + 10), which means "from the first element (0), advance 10 addresses (+ 10), and give me the contents (* operator) of that address as an int.
So you see, there is a mathematical relation between elements, they are all next to each other in memory.
Now, to your code...
When you call array= newElem();, your pointer array points to the newly allocated address. However, any previous address array was pointing to before is lost, which is causing both your unexpected behavior and memory leak.
When you first call array= newElem(), lets suppose an integer is allocated at the address A, and the next time a new integer is allocated at the address B, and so on...
On first iteration, with i = 0:
while( scanf("%d",&x)==1 ){
array= newElem();
// array points to A
array[i]=x;
// array[0] = x
// or *(array + 0) = x
// same as *(array) = x
i++;
// i = 1
}
Now you will MOST LIKELY have an error (i = 1):
while( scanf("%d",&x)==1 ){
array= newElem();
// address A is lost, and now array points to B
array[i]=x;
// array[1] = x; -> likely an ERROR
// *(array + 1) = x
i++;
// i = 2
}
On the second iteration, you try to access the address NEXT TO the new address array points to, which would be C, that is why you get a violation.
Your code does not maintain a relationship between the elements of the array, you are essentially creating single integers in every iteration, and then trying
to access then but you are actually accessing invalid memory addresses.
It is not a very simple concept at first, comment if you need further clarification.
I think I will understand this concept better if someone can assist me in a current project that I'm working on. I want to use C to edit data at specific memory addresses, using pointers. Specifically, I have two character arrays (strings) which I need to both read data from at specific locations, and also write to at specific locations.
I'm mostly confused about syntax of pointers, such as * and -> and &.
From my understanding, the * refers to the data kept at the current memory address of the pointer. So, for example, if I wanted to edit the data at the beginning memory address of a char *p, I would do something like: (*p) = 'c';
Now, what if I wanted do to alter a character at the 2nd memory address from the beginning of p?
Also, I understand that & refers to the location of the pointer. But I don't know how to use this syntax.
Here is my example:
int orig_length = strlen(original_string); //-1 for \0?
char *poriginal, *pnew_string;
poriginal = &original_string;
while(orig_length>0) {
k = 0;
j = 0;
while(isalpha(*(poriginal+j))) {
j++;
k++;
}
while(k > 0) {
*(pnew_string+(j-k)) = toupper(*(poriginal+k-1)); //toupper
k--;
}
if(*(poriginal+(j)) == '_') {
*(pnew_string+(j)) = ' ';
}
else {
*(pnew_string+(j)) = *(poriginal+(j));
}
orig_length = orig_length - j;
}
*(pnew_string+strlen(pnew_string)) = '\0'; //Syn? Is this actually necessary?
... //program continues...
By the way, this program is meant to take one string "now_i_understand!" and reverse each word, capitalize each word, switch _ to ' ', and leave other punctuation alone: "WON I DNATSREDNU!"
If what you are dealing with is an array of characters (and it is), use array syntax:
pnew_string[j+1] = poriginal[j+1];
Note that this syntax is equivalent to:
*(pnew_string + j + 1) = *(poriginal + j + 1);
but is more readable.
Dealing with most of the other cases you've got should be obvious given this example.
The * and & operators are inverses of each other. A pointer object hold the address of some other object in memory (or it old a null pointer, which doesn't point to any object).
The unary * operator takes a pointer operand, and gives you the object that it points to; this is called dereferencing.
The unary & operator takes an operand that refers to an object of any type, and gives you a pointer to that object. & is the address-of operator.
For example:
int obj = 42; /* obj is an object of type int; it currently holds the value 42 */
int *ptr; /* ptr is a pointer to an int */
ptr = &obj; /* ptr now holds the address of obj */
printf("obj = %d\n", obj); /* prints 42 */
printf("*ptr = %d\n", *ptr); /* also prints 42; *ptr is another name for obj */
The -> operator is shorthand for dereferencing a pointer and accessing a member of what it points to. The prefix must be a pointer to a struct or union. foo->bar means the same thing as (*foo).bar, where foo is a pointer and bar is the name of a member of what foo points to.
You can also perform arithmetic on pointers. If ptr is a pointer pointing to an element of an array, then ptr + 1 points to the next element of the array, ptr + 2 points to the element after that, and so forth.
The [] array indexing operator is actually defined in terms of pointer arithmetic. ptr[2] means exactly the same thing as *(ptr+2). Combine that with the fact that an array name, in most contexts, decays to a pointer to the array's first element, and with a little thought you'll see how arr[2] refers to the third element of the array arr (third because indexing starts at 0).
I strongly recommend sections 4 (Pointers) and 6 (Arrays and Pointers) of the comp.lang.c FAQ; it will likely explain this stuff better than I have.
I'm having a hard time understanding this program to illustrate pointers (from http://theocacao.com/document.page/234):
Below I don't understand why:
int * currentSlot = memoryBlock
isn't using &memoryBlock. I read the comment but don't get it. What is memoryBlock putting in there that &memoryBlock wouldn't? Won't both return the pointer to the set of ints created with calloc (assuming I understand what's been done that is)? What is really in * memoryBlock after calloc?
Then here, *currentSlot = rand();, how does the dereferencing work here? I thought the dereference would stop *currentSlot from giving the value of the memory address (the reference) to the actual value (no longer a reference but the value).
#include <stdio.h>
#include <stdlib.h> // for calloc and free
#include <time.h> // for random seeding
main ()
{
const int count = 10;
int * memoryBlock = calloc ( count, sizeof(int) );
if ( memoryBlock == NULL )
{
// we can't assume the memoryBlock pointer is valid.
// if it's NULL, something's wrong and we just exit
return 1;
}
// currentSlot will hold the current "slot" in the,
// array allowing us to move forward without losing
// track of the beginning. Yes, C arrays are primitive
//
// Note we don't have to do '&memoryBlock' because
// we don't want a pointer to a pointer. All we
// want is a _copy_ of the same memory address
int * currentSlot = memoryBlock;
// seed random number so we can generate values
srand(time(NULL));
int i;
for ( i = 0; i < count; i++ )
{
// use the star to set the value at the slot,
// then advance the pointer to the next slot
*currentSlot = rand();
currentSlot++;
}
// reset the pointer back to the beginning of the
// memory block (slot 0)
currentSlot = memoryBlock;
for ( i = 0; i < count; i++ )
{
// use the star to get the value at this slot,
// then advance the pointer
printf("Value at slot %i: %i\n", i, *currentSlot);
currentSlot++;
}
// we're all done with this memory block so we
// can free it
free( memoryBlock );
}
Thank you for any help.
Below I don't understand why:
int * currentSlot = memoryBlock
isn't using &memoryBlock.
Because both memoryBlock and currentSlot are pointers to int. &memoryBlock would be the address of a pointer to int, i.e. an int **.
What is "in" memoryBlock is a pointer to a block of memory.
Then here, *currentSlot = rand();, how does the dereferencing work here?
This is a rule of C: when a dereferencing expression like this occurs on the left-hand side of an expression, the right-hand side's value is stored in the memory location pointed to by the pointer being dereferenced.
int * memoryBlock;
memoryBlock is a variable which can hold the address of a memory block of integers. The size of the memoryBlock variable is the size of an address. Typically 4 or 8 bytes (sizeof(int*)). Its type is "pointer to int".
memoryBlock = calloc ( 5, sizeof(int) );
the memoryBlock variable is assigned the address of the start of the memory block able to hold 5 integers. The memory block size is 5 * sizeof(int) bytes.
memoryBlock + 1 is the address of the second integer in the block.
memoryBlock + 5 is one passed the address of the last integer in the block.
*memoryBlock is the content of the address (the first integer). type is integer.
*(memmoryBlock + 0) = 0;
*(memmoryBlock + 1) = 1;
*(memmoryBlock + 2) = 2;
*(memmoryBlock + 3) = 3;
*(memmoryBlock + 4) = 4;
// *(memmoryBlock + 5) = 5; illegal
Assigns integers to memory block.
Subscipt form same as above.
memmoryBlock[0] = 0;
memmoryBlock[1] = 1;
memmoryBlock[2] = 2;
memmoryBlock[3] = 3;
memmoryBlock[4] = 4;
// memmoryBlock[5] = 5; illegal
&memoryBlock is the address of the memoryBlock variable. This is not the address of the callocated space. It's type is int** "pointer to pointer to integer" not int*.
int ** pmemoryBlock;
pmemoryBlock is a variable which hold the address of an address of a memory block of integers. The size of pmemoryBlock is the size of an address. Typically 4 or 8 bytes (sizeof(int**)).
pmemoryBlock = &memoryBlock;
pmemoryBlock is assigned the address of a variable which holds the address of the start of the memory block able to hold 5 integers.
*pmemoryBlock is the address of the memory block.
**pmemoryBlock is the first integer in the memory block
*((*pmemoryBlock) + 0) is the first integer in the memory block
*((*pmemoryBlock) + 1) is the seconds integer in the memory block
...
memoryBlock is an array of integers (int*). (technically a pointer to an int but since it was allocated with enough room for 10 integers you can think of it as the start of an array)
*memoryBlock is the integer that memoryBlock is pointing to (the first int in the array). While the notation looks the same as the declariation it is actually dereferencing the value. IMHO it is poorly written as it should be declared
int* currentSlot = memoryBlock;
to make it more clear that it's a pointer to an integer, but that's a style choice.
&memoryBlock is the address of the pointer.
int * currentSlot = memoryBlock;
stores the pointer to the first slot in currentSlot. The program is then generating random numbers and putting them in each of the 10 clost by incrementing currentSlot (which internally is incrementing the pointer by the length of an integer.
Hope that helps.
In the code, memoryBlock is apointer to some memory that stores integers. That is, the actual value of the variable memoryBlock is the address just allocated. If you use &memoryBlock you get the address of where the variable is stored, not what it points to.
Lets take an example:
int foo = 5;
/* the variable "foo" is stored in memory,
and that memory contains the number 5 */
int bar = 7;
/* the variable "foo" is stored in memory,
and that memory contains the number 7 */
int *foo_pointer = &foo;
/* the variable "foo_pointer" is stored in memory,
and that memory contains the address of the variable "foo" */
foo_pointer = &bar;
/* the contents of the variable "foo_pointer" is no longer the address
of where the variable "foo" is in memory, instead it is the address
of where the variable "bar" */
I hope this makes some sense, and it helps a little.
It's not supposed to use &memoryBlock, which is the (int ** (heh!)) address of the the pointer into the memory you are clearing. In other words, memoryBLock (iff it's not NULL) points to (i.e., holds the address of) the first int in the calloc( )'ed memory. To reference that cleared-to-0 memory, you use *memoryBlock.
If you ever find yourself trying to use &memoryBlock, don't: it's never the right thing to do in the code fragment you posted.
HTH. If it doesn't help, go back to K&R and study pointers some more. Maybe a lot more.
int * is a pointer, which can be dereferenced. int ** is a pointer to a pointer, which can be dereferenced twice. So what does this mean? Well, a pointer is nothing more than an integer. Memory addresses just start from zero to its max range. For 32-bit systems, its range of addressable memory is 0 to 2^32-1 (or 4294967295). Each of this address has a byte value. If you have an int *, then it will access the address 4-bytes at a time.
Also, for simplicity, let's assume this is a virtual address, you can't just access all this memory, some will be protected (system), some are not valid (not committed). To gain more memory you can ask the system to allocate more from this range. sbrk in Linux, VirtualAlloc in Windows but you will be accessing them usually through C's malloc or calloc.
Let's say, you have starting from 0x100:
0x100: 'h', 'e', 'l', 'l', 'o', '\0'
So this string, occupies memory from 0x100 to 0x105 (including the null terminator). If you have a pointer:
char *p = 0x100;
Then you have:
p // 0x100
*p // 'h'
p+1 // 0x101
*(p+1) // 'e'
p += 2 // 0x102
*p // 'l'
p = 0x200;
p // now points to 0x200 in memory
*p // contains whatever value is in 0x200
If you have int pointers, then you are accessing memory 4-bytes at a time (or however big an int is on your system).
So with all that background, when you run calloc, it returns the address of the block you've requested.
int *memoryBlock = calloc(count, sizeof(int));
// memoryBlock is an array of int, assuming sizeof(int) == 4, then
// you have 40 bytes of memory starting from the address of what is
// returned by calloc.
memoryBlock++; // now memoryBlock is at base address + 4
*memoryBlock = 10; // now that address contains the value 10
(*memoryBlock)++; // now that address contains the value 11
memoryBlock++; // now memoryBlock is 4 bytes further