A deep understanding of the mysteries of C language pointers

Source: Internet
Author: User

A pointer is a special variable. The value stored in it is interpreted as an address in the memory. To understand a pointer, we need to understand four aspects of the pointer: the pointer type, the pointer type, the pointer value, or the memory zone pointed by the pointer, there is also the memory zone occupied by the pointer itself. Let's explain it separately.
First, declare several pointers for example:
Example 1:
(1) int * PTR;
(2) char * PTR;
(3) int ** PTR;
(4) int (* PTR) [3];
(5) int * (* PTR) [4];
Pointer type
From the syntax perspective, you only need to remove the pointer name in the pointer declaration statement, and the rest is the pointer type. This is the type of the pointer. Let's take a look at the type of each pointer in Example 1:
(1) int * PTR; // the pointer type is int *
(2) char * PTR; // the pointer type is char *
(3) int ** PTR; // the pointer type is int **
(4) int (* PTR) [3]; // the pointer type is int (*) [3]
(5) int * (* PTR) [4]; // the pointer type is int * (*) [4]
How is it? Is it easy to find the pointer type?
Type pointed to by pointer
When you access the memory area pointed to by the pointer, the type pointed to by the pointer determines what the compiler will regard the content in the memory area.
In terms of syntax, you only need to remove the pointer name and the pointer declarative * on the left of the name in the pointer declaration statement, and the rest is the type pointed to by the pointer. For example:
(1) int * PTR; // The Pointer Points to an int type.
(2) char * PTR; // The Pointer Points to a char type.
(3) int ** PTR; // The type pointed to by the pointer is int *
(4) int (* PTR) [3]; // The type pointed to by the pointer is int () [3]
(5) int * (* PTR) [4]; // The type pointed to by the pointer is int * () [4]
In pointer arithmetic operations, the type pointed to by the pointer has a great effect.
The pointer type (the pointer type) and the pointer type are two concepts. When you get familiar with C, you will find that, the concept of "type", which is mixed with pointers, is divided into two concepts: "pointer type" and "pointer type", which are one of the key points of mastering pointers. I have read a lot of books and found that some poorly written books bring together the two concepts of pointers. Therefore, the books seem to have conflicts and become more confused.
The pointer value, or the memory zone or address pointed to by the pointer.
The pointer value is the value stored by the pointer itself. This value will be treated as an address by the compiler rather than a general value. In 32-bit Program All types of pointer values are a 32-bit integer, because all the memory addresses in the 32-bit program are 32-bit long. The memory area pointed to by the pointer starts from the memory address represented by the pointer value, and the length is a memory area of Si zeof (type pointed to by the pointer. Later, we will say that the value of a pointer is XX, which means that the pointer points to a memory area with xx as the first address. We will say that a pointer points to a memory area, it is equivalent to saying that the pointer value is the first address of the memory area.
The memory zone pointed to by the pointer and the type pointed to by the pointer are two completely different concepts. In example 1, the pointer points to a type that already exists, but since the pointer has not been initialized, the memory zone it points to does not exist, or it is meaningless.
In the future, every time you encounter a pointer, you should ask: What is the type of this pointer? What is the pointer type? Where does this pointer point?
Memory occupied by the pointer itself
How much memory does the pointer occupy? You just need to use the sizeof function (pointer type) to test it. On a 32-bit platform, the pointer occupies 4 bytes.
The memory occupied by pointers can be used to determine whether a pointer expression is left.
Arithmetic Operations on pointers
The pointer can be added or subtracted from an integer. The meaning of this operation of pointer is different from that of addition and subtraction of common values. For example:
Example 2:
1. chara [20];
2. int * PTR =;
...
...
3. PTR ++;
In the preceding example, the pointer PTR is of the int type * and it points to the int type. It is initialized to the integer variable. In the next 3rd sentences, the pointer PTR is added with 1, and the compiler processes it like this: it adds the value of the pointer PTR with sizeof (INT), in a 32-bit program, is added with 4. Because the address is in bytes, the address pointed by PTR is increased by four bytes from the address of the original variable A to the high address.
Because the length of the char type is one byte, the PTR originally points to the four bytes starting from Unit 0th of array, this point points to the four bytes starting from Unit 4th in array.
We can use a pointer and a loop to traverse an array. For example:
Example 3:
Intarray [20];
Int * PTR = array;
...
// Here, the value assigned to the integer array is omitted. Code .
...
For (I = 0; I <20; I ++)
{
(* PTR) ++;
PTR ++;
}
In this example, the value of each unit in the integer array is added to 1. Since every loop adds the pointer PTR to 1, each loop can access the next unit of the array.

Let's look at the example:

Example 4:

1. chara [20];
2. int * PTR =;
...
...
3. PTR + = 5;
In this example, PTR is added with 5, and the compiler processes it like this: add the value of the pointer PTR to the value of the 5-bysizeof (INT ), in the 32-bit program, 5 is multiplied by 4 = 20. Because the address unit is byte, the current PTR points to the address, compared to the address pointed by the PTR after the addition of 5, move 20 bytes to the high address. In this example, if the PTR before 5 is not added, it points to the four bytes starting with unit 0th of array A. After 5 is added, the PTR points out of the valid range of array. Although this situation may cause problems in applications, it is possible in terms of syntax. This also reflects the flexibility of pointers.

If in the above example, PTR is subtracted from 5, the processing process is similar, except that the PTR value is subtracted from 5 by sizeof (INT ), the new PTR points to an address that moves 20 bytes to the lower address direction than the original PTR.
To sum up, after a pointer ptrold is added with an integer N, the result is a new pointer ptrnew. The type of ptrnew is the same as that of ptrold, ptrnew points to the same type as ptrold. The value of ptrnew will be increased by N multiplied by sizeof (type pointed to by ptrold) bytes than the value of ptrold. That is to say, ptrnew will point to a memory area that moves n byte by sizeof (type pointed by ptrold) to the high address direction than the memory area pointed to by ptrold.
After a pointer ptrold is subtracted from an integer N, the result is a new pointer ptrnew. The type of ptrnew is the same as that of ptrold, and the type of ptrnew is the same as that of ptrold. The value of ptrnew will be less than the value of ptrold by N multiplied by sizeof (type pointed to by ptrold) bytes, that is, the memory area to which ptrnew points will move n times of sizeof (type pointed by ptrold) bytes to the lower address direction than the memory area to which ptrold points.
Operators & and *
Here & is the address operator, * is... the book is called "indirect operator ".
& The operation result of A is a pointer, And the pointer type is a plus *. The Pointer Points to the type, and the Pointer Points to the address, that is the address of.
* P's computation results are varied. In short, the result of * P is what P points to. It has these characteristics: its type is P-pointed, and its occupied address is the address pointed to by P.
Example 5:
INTA = 12;
Intb;
Int * P;
Int ** PTR;
P = &;
// The result of & A is a pointer, whose type is int *, which is int and.
* P = 24;
// * P result. Here, the type of P is int, and the address occupied by P is the address pointed to by P. Obviously, * P is variable.
PTR = & P;
// The result of & P is a pointer. the pointer type is p type plus *. Here it is int **. The Pointer Points to the p type. Here it is int *. The Pointer Points to the address of P itself.
* PTR = & B;
// * PTR is a pointer, and the result of & B is also a pointer, and the types of the two pointers are the same as those pointed, therefore, it is no problem to assign a value to * PTR using & B.
** PTR = 34;
// * The PTR result is what PTR points to. Here it is a pointer. Perform another operation on this pointer. The result is an int type variable.
Pointer expression
If the final result of an expression is a pointer, the expression is called a pointer table.
Below are some examples of pointer expressions:
Example 6:
INTA, B;
Intarray [10];
Int * pA;
Pa = & A; // & A is a pointer expression.
Int ** PTR = & PA; // & PA is also a pointer expression.
* PTR = & B; // * PTR and & B are pointer expressions.
Pa = array;
Pa ++; // This is also a pointer expression.
Example 7:
Char * arr [20];
Char ** Parr = arr; // If arr is regarded as a pointer, arr is also a pointer expression.
Char * STR;
STR = * Parr; // * Parr is a pointer expression.
STR = * (Parr + 1); // * (Parr + 1) is a pointer expression.
STR = * (Parr + 2); // * (Parr + 2) is a pointer expression.
Since the result of a pointer expression is a pointer, the pointer expression also has four elements of the pointer: the pointer type, the type pointed to by the pointer, and the memory area pointed to by the pointer, memory occupied by the pointer itself.

Well, when the result pointer of a pointer expression has clearly occupied the memory of the pointer itself, the pointer expression is a left value, otherwise it is not a left value.
In Example 7, & A is not a left value because it does not occupy clear memory. * PTR is a left value, because * PTR pointer occupies the memory. In fact, * PTR is the pointer Pa. Since PA already has its own location in the memory, * PTR certainly has its own position.
Relationship between arrays and pointers
The array name can be regarded as a pointer. See the following example:
Example 8:
Intarray [10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, value;
...
...
Value = array [0]; // It can also be written as: value = * array;
Value = array [3]; // It can also be written as: value = * (array + 3 );
Value = array [4]; // It can also be written as: value = * (array + 4 );
In the above example, the array name array represents the array itself, and the type is int [10]. However, if we regard array as a pointer, it points to the 0th units of the array, and the type is int *, the Type pointed to is the type of the array unit, that is, Int. Therefore, it is not surprising that * array is equal to 0. Similarly, array + 3 is a pointer to the array's 3rd units, so * (array + 3) is equal to 3. Others.

Example 9:
Char * STR [3] = {
"Hello, thisisasample! ",
"Hi, Goodmorning .",
"Helloworld"
};
Chars [80];
Strcpy (S, STR [0]); // It can also be written as strcpy (S, * Str );
Strcpy (S, STR [1]); // It can also be written as strcpy (S, * (STR + 1 ));
Strcpy (S, STR [2]); // It can also be written as strcpy (S, * (STR + 2 ));
In the preceding example, STR is a three-unit array, and each unit of the array is a pointer, each pointing to a string. If the pointer array name STR is used as a pointer, it points to the cell 0th of the array. Its type is Char **, and it points to char *.
* STR is also a pointer. Its type is char *. It points to Char and its address is the string "Hello, thisasample! ", That is, the address of 'H. STR + 1 is also a pointer pointing to unit 1st of the array. Its type is Char **, and its type is char *.

* (STR + 1) is also a pointer. Its type is char * and it points to Char, which points to "Hi, Goodmorning. the first character 'h', and so on.

The following is a summary of the array name problem.

If an array typearray [N] is declared, the array name array has two meanings: First, it represents the entire array, and its type is type [N]; second, it is a pointer. the pointer type is type *. The Pointer Points to the type, that is, the type of the array unit. The memory area pointed to by the pointer is the unit 0th of the array, this pointer occupies a separate memory zone. Note that it is different from the memory zone occupied by the array unit 0th. The value of this pointer cannot be modified, that is, the expression similar to array ++ is incorrect.
In different expressions, array names can play different roles.
In the expression sizeof (array), the array name array represents the array itself. Therefore, the sizeof function measures the size of the entire array.
In the expression * array, array acts as a pointer. Therefore, the result of this expression is the value of unit 0th of the array. Sizeof (* array) measures the size of the array unit.
Expression Array + N (where n = 0, 1, 2 ,.....) In, array is a pointer, so the result of array + N is a pointer, its type is type *, it points to type, it points to the array number n. Therefore, sizeof (array + n) measures the pointer size.
Example 10:
Int array [10];
INT (* PTR) [10];
PTR = & array ;:
In the above example, PTR is a pointer and its type is int (*) [10]. It points to int [10]. We use the first address of the entire array to initialize it. In the statement PTR = & array, array represents the array itself.

As mentioned in this section, the sizeof () function is used to determine whether the sizeof (pointer name) is the size of the pointer's own type or the size of the type pointed to by the pointer? The answer is the former. For example:
INT (* PTR) [10];
In a 32-bit program, there are:
Sizeof (INT (*) [10]) = 4
Sizeof (INT [10]) = 40
Sizeof (PTR) = 4
In fact, sizeof (object) measures the size of the object's own type, rather than the size of other types.
Relationship between pointer and Structure Type
You can declare a pointer to a structure object.
Example 11:
Structmystruct
{
INTA;
Intb;
Intc;
}
Mystructss = {20, 30, 40 };
// Declare the structure object SS, and initialize the three SS members as 20, 30, and 40.
Mystruct * PTR = & SS;
// Declares a pointer to the structure object ss. Its type is mystruct *, and it points to mystruct.
Int * pstr = (int *) & SS;
// Declares a pointer to the structure object ss. However, its type is different from the type it points to and PTR.
How can I access the three member variables of SS through the pointer PTR?
Answer:
PTR->;
PTR-> B;
PTR-> C;
How can I access the three member variables of SS through the pointer pstr?
Answer:
* Pstr; // access a, a member of the SS.
* (Pstr + 1); // access B, a member of SS.
* (Pstr + 2) // access the SS member C.
Although I have adjusted the above Code on my msvc ++ 6.0, It is not formal to use pstr to access structure members. To explain why it is not formal, let's take a look at how to access the various elements of the array through pointers:
Example 12:
Intarray [3] = {35, 56, 37 };
Int * pA = array;
The method to access the three elements of the array through pointer PA is as follows:
* PA; // access to unit 0th
* (PA + 1); // access to unit 1st
* (PA + 2); // access to unit 2nd
The format is the same as the format of the informal method used to access structure members through pointers.
When all C/C ++ compilers arrange the elements of an array, they always store each array unit in a continuous storage area. There is no gap between the Unit and the unit. However, when each member of the structure object is stored, in a compiling environment, it may need word alignment, double-word alignment, or other alignment, you need to add several "fill bytes" between two adjacent members, which may lead to several gaps between each member.
Therefore, in example 12, even if * pstr accesses the first member variable A of the structure object SS, * (pstr + 1) cannot be guaranteed to access structure member B. Because there may be several Padding Bytes between member A and member B, maybe * (pstr + 1) will access these padding bytes. This also proves the flexibility of pointers. If your goal is to see whether there are any bytes filled with each structure member, hey, this is a good method.
The correct method for accessing structure members through pointers is to use the pointer PTR method in example 12.
Relationship between pointers and functions
You can declare a pointer as a pointer to a function. Intfun1 (char *, INT );
INT (* pfun1) (char *, INT );
Pfun1 = fun1;
....
....
INTA = (* pfun1) ("abcdefg", 7); // call a function through a function pointer.
You can use pointers as function parameters. In a function call statement, you can use a pointer expression as a real parameter.
Example 13:
Intfun (char *);
INTA;
Charstr [] = "abcdefghijklmn ";
A = fun (STR );
...
...
Intfun (char * s)
{
Intnum = 0;
For (INTI = 0; I {
Num + = * s; s ++;
}
Returnnum;
}
In this example, function fun counts the sum of the ASCII values of each character in a string. As mentioned above, the array name is also a pointer. In function calls, after STR is passed to the form parameter S as a real parameter, the STR value is actually passed to S, s points to the same address as STR points to, But STR and S occupy their own storage space. In the function body, the auto-increment 1 operation on S does not mean that the STR auto-increment 1 operation is performed at the same time.
Pointer type conversion
When we initialize a pointer or assign a value to a pointer, the left side of the value pair is a pointer, and the right side of the value pair is a pointer expression. In most cases, the pointer type is the same as that of the pointer expression, and the pointer type is the same as that of the pointer expression.
Example 14:
1. floatf = 12.3;
2. Float * fptr = & F;
3. int * P;
In the above example, if we want to point the pointer P to the real number F, what should we do? Is the following statement used?

P = & F;

NO. Because the pointer P is of the int type *, it points to the int type. The result of Expression & F is a pointer. the pointer type is float *, and the pointer type is float. The two are inconsistent. The direct assignment method is not feasible. At least in my msvc ++ 6.0, the assignment statement for the pointer requires that the types on both sides of the assignment number be consistent, and the types to be pointed to are also consistent. I have not tried it on other compilers, you can try it. To achieve our goal, we need to perform "forced type conversion":
P = (int *) & F;
if there is a pointer P, we need to change its type and type to tyep * type. The syntax format is:
(type *) P;
in this way, the forced type conversion result is a new pointer. the type of the new pointer is type *, and it points to type, it points to the address that the original Pointer Points. All properties of the original pointer P are not modified.
If a function uses a pointer as a form parameter, a pointer type conversion occurs when the real parameter and form parameter of the function call statement are combined.
example 15:
voidfun (char *);
INTA = 125, B;
fun (char *) & A);
...
...
voidfun (char * s)
{< br> charc;
C = * (S + 3); * (S + 3) = * (S + 0); * (S + 0) = C;
C = * (S + 2); * (S + 2) = * (S + 1); * (S + 1) = C;
}< BR >}< br> note that this is a 32-bit program, the Int type occupies four bytes, And the char type occupies one byte. Function fun is used to reverse the order of four bytes of an integer. Have you noticed? In a function call statement, the result of the real parameter & A is a pointer. Its type is int *, and its type is int. The pointer type of the parameter is char *, which points to Char. In this way, in the combination of real parameters and form parameters, we must perform a conversion from the int * type to the char * type. Using this example, we can imagine the conversion process of the compiler: the compiler first constructs a temporary pointer char * temp, and then runs temp = (char *) &, finally, pass the Temp value to S. So the final result is: the type of S is char *, which points to Char, and the address it points to is the first address of.

We already know that the pointer value is the address pointed to by the pointer. In a 32-bit program, the pointer value is actually a 32-bit integer. Can an integer be directly assigned to the pointer as the pointer value? Like the following statement:
Unsigned int;
Type * PTR; // The type is int, Char, or structure type.
...
...
A = 20345686;
PTR = 20345686; // Our purpose is to point the pointer PTR to the address 20345686 (decimal
)
PTR = A; // Our purpose is to point the pointer PTR to the address 20345686 (decimal)
Compile it. The result shows that the last two statements are all incorrect. So our goal cannot be achieved? No, there are other methods:
Unsigned int;
Type * PTR; // The type is int, Char, or structure type.
...
...
A = a certain number, which must represent a valid address;
PTR = (type *) A; // Ha, this is OK.
Strictly speaking, the type * here is different from the type * in the pointer type conversion. Here (type *) means to treat the value of the unsigned integer a as an address. It is emphasized that the value of a must represent a valid address. Otherwise, an invalid operation error occurs when you use PTR.

Think about whether or not we can take the address pointed to by the pointer as an integer. You can complete this operation. The following example shows how to take the value of a pointer as an integer and then assign this Integer as an address to a pointer:
Example 16:
INTA = 123, B;
Int * PTR = &;
Char * STR;
B = (INT) PTR; // take the pointer PTR value as an integer.
STR = (char *) B; // assign the value of this integer to the pointer STR as an address.
Now we know that we can take the pointer value as an integer, or assign an integer as an address to a pointer.
Pointer security issues
See the following example:
Example 17:
Chars = 'a ';
Int * PTR;
PTR = (int *) & S;
* PTR = 1298;
Pointer PTR is an int * type pointer, which points to the int type. It points to the first address of S. In 32-bit programs, s occupies one byte, And the int type occupies four bytes. The last statement not only changes the byte occupied by S, but also changes the three bytes in the high address direction adjacent to S. What are these three bytes? Only the compiled program knows, but the program writer is unlikely to know. Maybe these three bytes store very important data, maybe these three bytes are exactly a piece of code of the program, and because of your sloppy application of pointers, the value of these three bytes has been changed! This will cause a collapse error.
Let's take another example:
Example 18:
1. chara;
2. int * PTR = &;
...
...
3. PTR ++;
4, * PTR = 115;
This example can be fully compiled and executed. But do you see? After we perform the auto-increment 1 operation on the pointer PTR, the PTR points to a storage area adjacent to the high address of the shaping variable. What is in this bucket? We don't know. It may be a very important piece of data, or even a piece of code. The first sentence is to write a piece of data into this bucket! This is a serious error. So when using pointers, the programmer must be very clear about where my pointers actually point. When using pointers to access arrays, be sure not to go beyond the low-end and high-end limits of arrays. Otherwise, similar errors may occur.
In the forced type conversion of pointer: ptr1 = (type *) ptr2, if sizeof (ptr2 type) is greater than sizeof (ptr1 type ), therefore, it is safe to use the pointer ptr1 to access the storage zone pointed to by ptr2. If sizeof (ptr2 type) is smaller than sizeof (ptr1 type), it is insecure when ptr1 is used to access the bucket to which ptr2 points. As for why, readers should think about it in combination with example 17.

From http://embedfans.com/C/2007181016375897.htm

//////////////////////////////////////// ///////////////////////////////////////

All the complex pointer declarations in C language are made up of various declarations nested. How can we interpret complex pointer declarations? The left-right rule is a well-known and commonly used method. However, the right-left rule is not actually the content in the C standard. It is a method summarized from the C standard statement. The C-standard declaration rules are used to solve how to create a declaration, while the right-left rule is used to identify a declaration. The two are the opposite. The original English version of the right-left rule is as follows:
The right-left rule: start reading the declaration from the innermost parentheses, go right, and then go left. when you encounter parentheses, the direction shoshould be reversed. once everything in the parentheses has been parsed, jump out of it. continue till the whole declaration has been parsed.
The English translation is as follows:
Right left rule: first, start from the parentheses in the innermost part, and then look to the right, then to the left. When parentheses are encountered, the reading direction should be dropped. Once everything in the parentheses is parsed, the parentheses appear. Repeat this process until the entire declaration is parsed.
I want to make a small correction to this rule. It should be read from undefined identifiers rather than from parentheses. The reason is that there may be multiple identifiers in a declaration, but there is only one undefined identifier.
Now we can use some examples to discuss the application of the right-left rule, starting from the simplest:

INT (* func) (int * P );
First, find the undefined identifier, that is, func, which has a pair of parentheses and a * sign on the left. This indicates that func is a pointer and jumps out of the parentheses, first look at the right, it is also a parentheses, which means (* func) is a function, and func is a pointer to this type of function, is a function pointer, this type of function has an int * type parameter, and the return value type is int.

INT (* func) (int * P, INT (* f) (int *));
Func is enclosed by a pair of parentheses, and there is a "*" on the left, which indicates that func is a pointer. It jumps out of the brackets and there is a bracket on the right. Then func is a pointer to the function, this type of function has parameters such as int * and INT (*) (int *), and the return value is of the int type. Let's take a look at the func parameter int (* f) (int *). Similar to the previous explanation, F is also a function pointer. the pointer to a function has an int * type parameter and the return value is int.


INT (* func [5]) (int * P );
The right side of func is a [] Operator, indicating that func is an array with five elements, and there is a * on the left of func, indicating that the element of func is a pointer, note that * not modifying func, but modifying func [5] is because the [] operator has a higher priority than *, and func is first combined, therefore, * modifies func [5]. Jump out of this bracket and look at the right. It is also a pair of parentheses, indicating that the element of the func array is a pointer of the function type. It points to the function with an int * type parameter and the return value type is int.


INT (* func) [5]) (int * P );
Func is enclosed by parentheses, and there is a * on the left. func is a pointer, out of parentheses, and a [] operator number on the right, which indicates that func is a pointer to an array, to the left, there is a "*" on the left, indicating that the element of this array is a pointer, and then the brackets appear on the right, indicating that the element of this array is a pointer to the function. To sum up, func is a pointer to an array. The elements of this array are function pointers. These pointers point to functions with int x parameters and return values of the int type.


INT (* func) (int * p) [5];
Func is a function pointer. This type of function has an int * type parameter. The returned value is a pointer to an array. The elements of the array to which it points are arrays with five int elements.
Note that some complex pointer declarations are invalid, for example:


Int func (void) [5];
Func is a function that returns an array with five int elements. However, the function return value in C language cannot be an array. This is because if the function return value is an array, what receives the content of this array must also be an array, however, the array name in C language is a right value, which cannot be used as the left value to receive another array. Therefore, the return value of the function cannot be an array.

Int func [5] (void );
Func is an array with five elements. All elements of this array are functions. This is also invalid because the elements of the array must be of the same type and the memory space occupied by each element must be the same. Obviously, the function cannot meet this requirement, even if the function type is the same, the space occupied by the function is usually different.
As an exercise, the following lists several complex pointer declarations for readers to resolve themselves. The answer is placed in chapter 10.

INT (* func) [5] [6]) [7] [8];
INT (* func) (int *) [5]) (int *);
INT (* func [7] [8] [9]) (int *) [5];

In reality, when a complex pointer needs to be declared, if the entire declaration is written in the form shown above, the readability of the program is greatly impaired. Typedef should be used to separate declarations layer by layer to enhance readability. For example, for declarations:
INT (* func) (int * p) [5];
It can be decomposed as follows:
Typedef int (* para) [5];
Typedef para (* func) (int *);
This makes it easier to see.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.