https://www.bilibili.com/video/BV1bo4y1Z7xf
https://gist.github.com/LittleBlacklb/ef27515ad9aeae13f956d6c5f302a4d5
There must be some grammatical errors here, please forgive me :(
<data type> *<variable name>;
: The pointer to the <data type>
of <variable name>
&<variable>
: Return the address of the variable
*<variable>
: Return the value at variable's address To access the address of the variable in format
The asterisk meaning between int* p
and *p
are not the same.
int*
is a type that a pointer point to a data of int type.
*p
is to dereference the address which stored in variable p.
int a = 1024;
int *p;
p = &a; // Assume variable `a` 's address is 2077
cout << p << endl; // 2077 in decimal
cout << p + 1 << endl; // 2081 in decimal
int a = 1025;
int* p;
p = &a;
printf("Address=%d; value=%d\n", p, *p);
char* p0; // 1 char: 1 byte = 8 bit
p0 = (char*)&a; // Cast int* to char*
// 1025 in memory (small-endian order):
// ... 00000000 00000000 00000100 00000001 ...
// ...(p + 3) ^ (p + 2) ^ (p + 1) ^ (p + 0) ^ ...
// '^' means toward bit
printf("%d\n", (int)*p0); // 0000100 => 1
printf("%d\n", (int)*(p0 + 1)); // 00000001 => 4
void* <variable name>;
It can't be used to print the value that it points.
It can be used to print itself address.
char c[] = "ABC";
: It will be stored in the space for array (Stack).
const char* c = "Hello";
: It will be stored as compile time constant, so it cannot be modified (Like: c[0] = 'a'
)
The relationship between Array & Pointer.
arr[x]
<==>*(arr+x)
(You need to know that
arr
is a const variable, so it cannot be assigned (Like:arr = var
)It just the same as the relationship between Reference & Pointer
int &a = var
<==>int* const a = &var
return a
<==>return *a
// ...
int get_size(int arr[])
{
return sizeof(arr) / sizeof(arr[0])
}
Most of the time, return result is 1 (Depend on the platfrom)
Because the declaration of
int arr[]
is actually a int pointer which points to the first address of the array.Compiler translates
int arr[]
=>int* arr
So the variable of
arr
's size is the size of pointer.The purpose is to reduce the time and space cost.(It don't need to copy the array)
2-dimensional array:
a[i][j]
=>*(a[i]+j)
=>*(*(a+i)+j)
a
's type:int (*)[]
a[i]
's type:int*
3-dimensional array:
a[i][j][k]
=>*(a[i][j] + k)
=>*(*(a[i] + j ) + k )
=>*(*(*(a + i) + j ) + k
a
's type:int(*)[][]
a[i]
's type:int(*)[]
a[i][j]
's type:int*
Yes! They are not the same type. You can't consider them as the same type!
int arr[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int (*p)[3] = arr;
printf("%d\n", p);
printf("%d\n", *p);
This circumstance only happens in static creation!
p
and *p
's output are both equal
Differences:
p
: It's a one-dimensional pointer;
*p
: It's a int*
pointer.
type of array inequals to pointer
In the other word, array is a special pointer.
-
It's a fake-pointer (pointer's address = the address it's point to) Because the static array is continuous. But dynamic multi-dimension array is not continuous from row to row.
-
It needs each row's capacity. For example:
sizeof(int[3]) = 12
As we all know,sizeof(int) * 3 = 12 bytes
So when you do operator like+
, C can know plus 1 equal to how many bytes
Static:
int arr[3][3];
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
{
// These following three are all equivalent
*(arr[y]+x) = 3 * y + x;
*(*(arr + y) + x) = 3 * y + x;
*((*arr + 3 * y) + x) = 3 * y + x; // Important!
}
}
int (*p)[3] = arr;
// All equal
printf("%d\n", p);
printf("%d\n", *p);
int b[3][1];
int (*p)[1] = b;
// int **p = b; // Syntax Error
Dynamic:
int **arr = (int **)calloc(3, sizeof(int *));
for (int y = 0; y < 3; y++)
{
*(arr + y) = (int *)calloc(3, sizeof(int));
for (int x = 0; x < 3; x++)
{
// ...
}
}
int** p = arr;
// Not equal
printf("%d\n", p);
printf("%d\n", *p);
It doesn't need []
type for helping.
Because it's structure is different from static array.
It's discontinuous, and is similar to deque
in STL:
一段一段的连续空间's beginning address are different.
注意高字节在左边,低字节在右边
1 1 1 1
High Bit Low Bit
0b1001111
Big Endian
Low address in mem -------------> High address in mem
1 0 0 1 1 1 1
High Bit <----------------------- Low Bit
Small Endian
Low address in mem -------------> High address in mem
1 1 1 1 0 0 1
Low Bit <------------------------ High Bit
0b10010101
The bold underlined bit above called Least Significant Bit In Big-Endian order, LSB refers to the rightest bit.
-
代码区:存放函数体的二进制代码,由操作系统进行管理的
-
全局区:存放 全局变量 和 静态变量 以及常量
-
栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等
-
堆区:由**程序员分配和释放**,若程序员不释放,程序结束时由操作系统回收
C:
Functions:
void *malloc(size_t size) void *calloc(size_t nitems, size_t size)` void *realloc(void *ptr, size_t size) void free(void *ptr)
C++:
Key Words:
new <variable>
delete <variable>
delete[] <variable>
Signature:
void *malloc(size_t size)
size_t
: Positive number. The exact data type depend on the platform (unsigned int
, etc.)
Usage:
int* p = (int*)malloc(4 * sizeof(int))
Replacing
sizeof(int)
with4
is not recommanded. Because the space of a data type depends on the compiler(platform)Malloc function return a generic pointer (
void*
), so we need to do a type casting.
Signature:
void *calloc(size_t nitems, size_t size)`
size_t nitems
: Numbers of elements of specific data type
Difference:
-
It can be more convenient to allocate a continuous memory.
-
It will initialize the allocated memory with
0
.
Signature:
void *realloc(void *ptr, size_t size)
Application Scenarios:
- The new memory block may bigger than the original one.
- The function will mallocate a new memory block & copy the original data to there.
- If the old memory block's adjacency is available to use, the function will expand the old memory block.
- The new memory block may less than the original one.
- The function will free the unnecessary memory block.
//...
int n;
printf("Enter the size of array:\n");
scanf("%d", &n);
int *arr = (int*)calloc(n, sizeof(int)); // Dynamically allocated array
// arr = {0, 0, 0, ...} (n>3)
// ...
free(arr);
Some machine or compiler may allows program to r/w memory block that freed. But sometimes may get crash.
// ...
realloc(NULL, n*sizeof(int)); // equivalent to malloc;
realloc(arr, 0); // equivalent to free;
In C or C++:
int* p;
p = (int*)alloc(sizeof(int));
*p = 0x400;
free(p)
In C++:
int* p;
p = new int;
*p = 0x400;
delete p;
When you alloc a continuous space, you can use the space as a array.
In C or C++:
// ...
int* p;
const int SIZE = 4;
p = (int*)alloc(SIZE * sizeof(int)) // Allocate a 16 byte continuous space
for (int i=0; i<4; i++, p++)
{
// p[i] = i;
*p = i;
}
free(p)
In C++:
int* p;
const int SIZE = 4;
p = new int[4]; // Allocate a 16 byte continuous space
for (int i=0; i<4; i++, p++)
{
// p[i] = i;
*p = i;
}
delete[] p;
Normal:
//...
void func()
{
printf("void func(): called")
char chars = "1145141919810"; // 13 bytes
}
int main()
{
for (int i = 0; i < 100; i++) func();
return 0;
}
The program's usage of the memory won't be raised up after finish calling the func()
Memory Leak:
//...
void func()
{
printf("void func(): called")
char* chars = (char*)calloc(1145, sizeof(char)); // 1145 bytes
// char* chars = new char[1145];
}
int main()
{
for (int i = 0; i < 100; i++) func();
return 0;
}
The program's usage of the memory will be raised up after finish calling the func()
Reason: The allocated memory block in heap isn't deallocated after use.
Solution: Add a
free(chars)
ordelete[] chars
at the end line of the func()
In Java, C#, etc. The problem can't be happened, because they have their own garbage collection mechanism.
//...
int f1(int a) {/* ... */}
int f2(int* a) {/* ... */}
int main() {f1();f2();return 0}
Concept:
int main();
: In C/C++ called Calling function
int f1(int a);
andint f2(int* a)
: Call Called function
int f1(var);
: Call Call by value
int f1(*var);
: Call Call by reference
The correct operation of returning pointer from function:
int* rtnAPointer()
{
int* p = (int*)malloc(sizeof(int));
*p = 0x1bf52;
return p;
}
int main()
{
int* p = rtnAPointer();
*p += 1919810;
printf("%d\n", p);
free(p);
return 0;
}
A pointer which stores a function entry address.
Initialization syntax: <return type> (*<pointer name>)(<type>, ...);
Example:
void (*fp)(int, char);
Counterexample:
int *fp();
This declare a function that return int*
, not a function pointer.
Call syntax: *(<pointer name>)(<type>, ...)
or <pointer name>(<type>, ...)
Example:
*(f)(0x1bf52, 33);
f(0x1bf52, 33);
Why these two syntax are both correct?
You can compare this with array's syntax:
int arr[]
<==>int* arr
*(f)()
<==>f()
// ...
void f0() {printf("f0() called");}
void f1(void (*func)()) {func();}
int main() {
f1(f0);
return 0;
}
What's the meaning of the callbacks?
In C library function, qsort
use it.
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
base − This is the pointer to the first element of the array to be sorted.
nitems − This is the number of elements in the array pointed by base.
size − This is the size in bytes of each element in the array.
compar − This is the function that compares two elements.
The reference example from:
#include <stdio.h>
#include <stdlib.h>
int values[] = { 88, 56, 100, 2, 25 };
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int main()
{
int n;
printf("排序之前的列表:\n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
qsort(values, 5, sizeof(int), cmpfunc);
printf("\n排序之后的列表:\n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
return 0;
}
- Memory is byte addressable
- Memory is an array of bytes
- Each byte has a memory address
- Smallest data that can be addressed is a byte
- The reason that why boolean data type is 1 byte.
- Each address has 32 bits (ARM Cortex-M)
- The value of a pointer is simply the memory address of some variable
- If a variable occupies multiple bytes in memory, its address is the lowest address of all bytes it occupies.
The pink address is this integer's This is small-endian order
/*
* @Date: 2022-07-21 22:39:45
* @LastEditors: littleblackLB
* @LastEditTime: 2022-07-22 00:16:55
* @FilePath: \Cpp\src\Test.cpp
*/
#include <iostream>
using namespace std;
// 一个指针数组,拥有三个元素,每个元素指向一个函数原型为 void func()
typedef void (*(ARR[3]))();
// 一个函数指针返回一个数组,这是一个指针数组,容量为10,
// 每个元素指向一个函数原型为 void func()
typedef ARR *(*FUNC)(); // 等价于 typedef void(*(*(*FUNC)())[3])();
void func2()
{
printf("%d\n", 888);
}
void func3()
{
printf("%d\n", 889);
}
void func4()
{
printf("%d\n", 890);
}
ARR *func1()
{
ARR *rtn = new ARR[3];
// 解引用rtn指针到数组头指针,解数组头指针,并赋值为func2
**rtn = func2; // 等价于*rtn[0] = func2;
*rtn[1] = func3;
*rtn[2] = func4;
return rtn;
}
int main(int argc, char const *argv[])
{
system("chcp 65001");
FUNC f = func1;
ARR *fs = (*f)(); // 等价于ARR *fs = f();
for (int i = 0; i < 3; i++)
{
(*fs[i])(); // 等价于fs[i]();
}
delete[] fs;
system("pause");
return 0;
}