On a 32-bit machine, where addresses are 32 bits in size, the entire memory space begins at 0x00000000 (in hex, each 0 represents 4 bits of 0) and ends at 0xFFFFFFFF (recall that 0x indicates hexadecimal, and that each F represents four binary 1’s).
intmain() { char buf[512]; // Buffer to hold our modified path. char *p; // Pointer used to manipulate buf. char path[] = "folder"; // Original path.
// Copy the string "folder" into buf. strcpy(buf, path); // Set pointer p to the end of the string in buf. p = buf + strlen(buf); // Append a '/' character at the current position and then increment p. *p++ = '/'; // Append the null terminator to complete the string. *p = '\0';
// Output the modified string. printf("Modified path: %s\n", buf);
intmain() { // Initialize 2D array with given values int a[2][3] = { {1, 2, 3}, {3, 5, 6} };
printf("Array values and pointers:\n\n");
// Print array values and addresses for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { // Print the value printf("a[%d][%d] = %d\n", i, j, a[i][j]);
// Print the memory address (pointer) printf("Address of a[%d][%d]: %p\n", i, j, &a[i][j]);
printf("\n"); } }
// Additional information about the array and pointers printf("Base address of array a: %p\n", a); printf("Address of first row (a[0]): %p\n", a[0]); printf("Address of second row (a[1]): %p\n", a[1]);
// Show how array can be accessed using pointer arithmetic printf("\nAccessing using pointer arithmetic:\n"); for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { printf("a+%d = %p\n", i, a+i); printf("*(a+%d) = %p\n", i, *(a+i)); printf("*(a+%d)+%d = %p\n", i, j,*(a+i)+j); printf("(a+%d+%d) = %p\n", i, j, (a+i+j)); printf("*(*(a+%d)+%d) = %d\n", i, j, *(*(a+i)+j)); printf("\n"); } }
why a+i and *(a+i) have same pointer , but (a+i)+j and (a+i+j) have different pointer address result
This is a great question that gets to the heart of how 2D arrays and pointers work in C! Let me explain the key difference:
a+i vs *(a+i):
a+i is a pointer to the entire row i (a pointer to an array of 3 integers)
*(a+i) dereferences that pointer, giving you a pointer to the first element of row i
They appear to have the same address value when printed because they both point to the same memory location (the start of row i), but they have different types:
a+i is of type int (*)[3] (pointer to an array of 3 integers)
*(a+i) is of type int* (pointer to an integer)
(a+i)+j vs (a+i+j):
(a+i)+j is invalid - it’s trying to add j to a pointer to a row, which would skip j rows
*(a+i)+j is correct - it’s adding j to a pointer to the first element of row i
(a+i+j) is adding j to a pointer to row i, which is interpreted as jumping j rows ahead
The difference in addresses occurs because:
When you add j to a+i, you’re moving j rows forward (each row is 3 integers × sizeof(int) bytes)
When you add j to *(a+i), you’re moving j integers forward (each integer is sizeof(int) bytes)
This is why (a+i+j) and *(a+i)+j point to completely different memory locations. The first is jumping multiple rows ahead, while the second is moving within the same row.
For a 2D array access, the correct pointer arithmetic is *(*(a+i)+j), which corresponds to a[i][j].
String
The compiler puts the string literals into a read only region of memory because the literal may get reused, and thus should not be changed. Consider the following code:
1 2
char * str1 = "Hello"; str1[0] = 'J'; // this would crash, but suppose it did not
Mutable Strings
When we want to modify a string, we need the string to reside in writeable memory, such as the frame of a function or memory that is dynamically allocated by malloc (which you will learn about in Course 4).
1 2 3 4
char str[] = "Hello World\n"; This code behaves exactly as if we wrote: char str[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l''d', '\n', '\0'};
intmain( ) { int a[2][3] = {[0][0]=1, [0][1]=2, [0][2]=3, [1][0]=4, [1][1]=5, [1][2]=6}; int i, j; int *p = *a; int(*q)[3] = a; printf(format: "a %p %p\n", a, a + 1); printf(format: "q %p %p\n\n", q, q + 1);
可以理解 const修饰 * p 那么p的指向不能改 const修饰 int * 那么 *p的值 不能改。
We have declared p as a pointer to a const int—that is, p points at a int, and we are not allowed to change that int. We can change where p points (e.g., p = &y; is legal—if y is an int). However, changing the value in the box that p points at (*e.g., p = 4;) is illegal—we have said that the int which p points at is const. If we do try to write something like *p = 4;, we will get a compiler error like this:
First, we are not constrained to having each row be the same size as the other rows.
Second, in the array of pointers representation, myMatrix [i] is an lvalue (recall that it is not if we just declare an array with multiple dimensions).
Third, we can have two rows point at the exact same array (aliasing each other)
I can explain the differences between these two parameter declarations in C.
In the function average_score(int *p, int n), the parameter *p is a pointer to an integer. This means:
It points to a single integer value
It can also point to the first element of a 1D array of integers
You can traverse through consecutive memory locations using pointer arithmetic (as done with *(p + i))
In the function find_num(int (*p)[N], int num), the parameter int (*p)[N] is a pointer to an array of N integers. This means:
It points to a row of a 2D array
Each “step” when using p + 1 advances by N integers (a whole row), not just one integer
To access individual elements, you need double dereferencing as seen in *(*(p + num) + i)
The main practical difference is how you navigate through memory:
With int *p, adding 1 to the pointer moves to the next integer (4 bytes typically)
With int (*p)[N], adding 1 to the pointer moves N integers forward (N*4 bytes typically)
This is why in your find_num function, *(p + num) gives you a pointer to the beginning of row num, and then *(*(p + num) + i) accesses the individual elements in that row.
函数与指针
指针函数
是一个函数,返回值是指针。
返回值 * 函数名 (形参)
如:int * fun(int);
Function Pointe函数指针
是一个指针,指向函数。
类型 (* 指针名) (形参)
如: int (*p)(int);
this syntax makes sense, as it looks a lot like the normal declaration of a function—the return type comes first, followed by the name, followed by the parameters in parenthesis .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
int * find_num(int (*p)[N], int num)// 学生的成绩,每行开头指这个学生,后续的列是他的成绩 { if(num>M-1) returnNULL; return *(p+num); }
intmain() { int i, j; int a[M][N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
intmain() { int a = 3, b = 5; int ret; // int (*p)(int, int); // int (*q)(int, int);
int (*funcp[2])(int, int);
// p = add; // q = sub;
funcp[0] = add; funcp[1] = sub;
// ret = p(a, b); // ret = q(a, b);
for (int i = 0; i < 2; i++) { ret = funcp[i](a, b); // 作用与函数 * 可以省略 printf("ret = %d\n", ret); }
exit(0); }
As with other types, we can use typedef with function pointers. The syntax is again more similar to function declarations than to other forms of typedef. We might re-write our previous example to use typedef, so that it is easier to read:
1 2 3 4 5 6 7
typedefint(*int_function_t)(int);
voiddoToAll(int * data, int n, int_function_t f) { for (int i = 0; i < n; i++) { data[i] = f(data[i]); } }