The difference between struct and class in c,
To put it simply, struct is a value type. Creating a struct instance is allocated to the stack. A class is a reference type. Creating a class-type instance is assigned to the managed stack. However, the difference between struct and class is far more than that. This article mainly includes:
■ In summary
■ Experience the differences between struct and class from the perspective of assignment
■ Experience the difference between struct and class from the perspective of parameter value passing
■ Experience the difference between struct and class from struct type attributes and struct reference type attributes
■ Experience the difference between struct and class from the constructor
■ Evaluate the difference between struct and class by assigning initial values to type members
■ When to use struct and class?
In summary
In summary, the differences between struct and class are reflected in:
● The class is the reference type, and the struct is the value type.
● Create a class instance on the hosting stack and create a struct instance on the stack
● Class instance assignment, which assigns a reference address, a struct instance assignment, and a value
● The class is passed as the parameter type, the referenced address is passed, the struct is passed as the parameter type, and the value is passed
● No default parameter constructor for the class and no parameter constructor for struct
● Classes support inheritance, and struct does not support inheritance
● Classes tend to be "Object-Oriented" and are used for complex and large data. struct tends to be "simple value", for example, less than 16 bytes, and the structure is simple.
● It is easy for a class member to assign an initial value, and it is difficult to assign an initial value to a struct member.
● Class instances can only be created through new SomeClass (). struct instances can be created either through new SomeStruct () or through SomeStruct myStruct;
Experience the differences between struct and class from the perspective of assignment
Assign a value to the reference type. The address is assigned to the variable.
Class Program {static void Main (string [] args) {SizeClass sizeClass = new SizeClass () {Width = 10, Length = 10}; Console. writeLine ("before assignment: width = {0}, length = {1}", sizeClass. width, sizeClass. length); var copyOfSizeClass = sizeClass; copyOfSizeClass. length = 5; copyOfSizeClass. width = 5; Console. writeLine ("after assignment: width = {0}, length = {1}", sizeClass. width, sizeClass. length); Console. readKey () ;}} public class SizeClass {public int Width {get; set;} public int Length {get; set ;}} public struct SizeStruct {public int Width {get; set ;}public int Length {get; set ;}}
Above, when sizeClass is assigned to the copyOfSize variable, the address pointed to by sizeClass is assigned to the copyOfSize variable, and the two variables both point to the same address. Therefore, changing the value of the copyOfSizeClass variable is also equivalent to changing the value of the sizeClass.
Struct type assignment, which is a full copy, with an identical variable added to the stack
Class Program {static void Main (string [] args) {SizeStruct sizeStruct = new SizeStruct () {Length = 10, Width = 10}; Console. writeLine ("before assignment: width = {0}, length = {1}", sizeStruct. width, sizeStruct. length); var copyOfSizeStruct = sizeStruct; copyOfSizeStruct. length = 5; copyOfSizeStruct. width = 5; Console. writeLine ("after assignment: width = {0}, length = {1}", sizeStruct. width, sizeStruct. length); Console. readKey ();}}
Previously, when sizeStruct is assigned to the copyOfSizeStruct variable, it is a full copy. Changing the value of copyOfSizeStruct does not affect sizeStruct.
Experience the differences between struct and class from the perspective of parameter value passing
Parameters of the reference type pass the address
class Program { static void Main(string[] args) { List<string> temp = new List<string>(){"my","god"}; temp.ForEach(t => Console.Write(t + " ")); Console.ReadKey(); } public static void ChangeReferenceType(List<string> list) { list = new List<string>(){"hello", "world"}; } }
Result: my god
Why not hello world?
→ The temp on the stack points to a collection instance on the managed stack.
→ When temp is put in the ChangeReferenceType (temp) method, the essence is to assign the address pointed by temp to the variable list.
→ In the ChangeReferenceType (List <string> list) method, the variable list points to the address of another set instance.
→ However, the temp point address remains unchanged.
Let's change the internal implementation method of ChangeReferenceType (List <string> list.
class Program { static void Main(string[] args) { List<string> temp = new List<string>(){"my","god"}; ChangeReferenceType(temp); temp.ForEach(t => Console.Write(t + " ")); Console.ReadKey(); } public static void ChangeReferenceType(List<string> list) { list.Clear(); list.Add("hello"); list.Add("world"); } }
Result: hello world
Why not my god?
→ The temp on the stack points to a collection instance on the managed stack.
→ When temp is put in the ChangeReferenceType (temp) method, the essence is to assign the address pointed by temp to the variable list.
→ In the ChangeReferenceType (List <string> list) method, clear the instances that both temp and list point to, and add two elements "hello" and "world ".
→Because list and temp point to the same instance, changing the list to the instance is equivalent to changing the instance that temp points.
The above shows that the parameter of the reference type passes the address.
The Value Type passed by the struct parameter is
class Program { static void Main(string[] args) { Size s = new Size(){Length = 10, Width = 10}; ChangeStructType(s); Console.Write("Length={0},Width={1}", s.Length,s.Width); Console.ReadKey(); } public static void ChangeStructType(Size size) { size.Length = 0; size.Width = 0; } } public struct Size { public int Length { get; set; } public int Width { get; set; } }
Why is the Length and Width not 0?
→ Size of the variable on the stack
→When the s variable is assigned to the size variable in ChangeStructType (Size size) through ChangeStructType (size), the essence is that another variable size is created on the stack, the value of size is exactly the same as that of s.
→ Change the Size value within ChangeStructType (size Size), which is irrelevant to variable s.
Experience the difference between struct and class from struct type attributes and struct reference type attributes
Assume there is a struct with a struct type attribute.
The following table size and TvSize attributes of the struct type Room are available. How can we modify the attribute values of the struct type through the Room instance?
Class Program {static void Main (string [] args) {Room r = new Room () {TableSize = new Size () {Length = 100, Width = 80 }, tvSize = new Size () {Length = 10, Width = 8 }}; r. tableSize. length = 0; Console. writeLine ("the current table size is: length = {0}, width = {1}", r. tableSize. length, r. tableSize. width); Console. readKey () ;}} public struct Size {public int Length {get; set;} public int Width {get; set ;}} public struct Room {public Size TableSize {get; set ;}public Size TvSize {get; set ;}}
In the preceding example, r. TableSize. Length = 0. Here, an error is returned: the value of r. TableSize cannot be modified because it is not a variable. Indeed, r. tableSize is only a copy of the Size and is not assigned to other variables, so r. tableSize is temporary and will be automatically recycled. it is meaningless to assign a value to it.
If you want to modify r. TableSize, you only need to change r. TableSize. Length = 0; to the following:
R. TableSize = new Size () {Length = 0, Width = 0 };
It can be seen that changing an attribute of the struct type's struct type does not work, because the preceding r. TableSize is only a copy and is temporary and will be automatically recycled. To change the struct type attribute of the struct type, you need to assign a complete Size instance to r. TableSize as above.
Suppose there is a struct, which has the property of the reference type?
Here, rooms of the struct type have reference type attributes, TableSize and TvSize. How can I modify the attribute values of the reference type through the Room instance? In addition, we define an event in class Size. An event is triggered when a value is assigned to the Size attribute, prompting that the attribute value of the size class has changed.
Class Program {static void Main (string [] args) {var oneSize = new Size () {Length = 10, Width = 10}; var twoSize = oneSize; oneSize. changed + = (s, e) => Console. write ("Size changed ~~ "); OneSize. length = 0; Console. readKey () ;}} public class Size {private int _ length; private int _ width; public event System. eventHandler Changed; public int Length {get {return _ length;} set {_ length = value; OnChanged () ;}} public int Width {get {return _ width ;} set {_ width = value; OnChanged () ;}} private void OnChanged () {if (Changed! = Null) {Changed (this, new EventArgs () ;}} public struct Room {public Size TableSize {get; set ;}public Size TvSize {get; set ;}}
Run, show: The Size has changed ~~
The actual modification to oneSize. Length is that oneSize. Length points to the instance on the managed stack.
Experience the difference between struct and class from the constructor
Struct type contains implicit default no-argument Constructor
class Program { static void Main(string[] args) { var size = new SizeStruct(); Console.WriteLine("length={0},width={1}", size.Length, size.Width); Console.ReadKey(); } } public struct SizeStruct { public int Length { get; set; } public int Width { get; set; } }
Why didn't we give SizeStruct a non-argument constructor definition without an error?
-- The struct type has an implicit no-argument constructor and assigns default values to all members. The default value of int type attribute members is 0.
Class does not contain implicit parameter-free Constructor
class Program { static void Main(string[] args) { var size = new SizeClass(); Console.WriteLine("length={0},width={1}", size.Length, size.Width); Console.ReadKey(); } } public class SizeClass { public int Length { get; set; } public int Width { get; set; } public SizeClass(int length, int width) { Length = length; Width = Width; } }
Run, error: SizeClass constructor that does not contain 0 Parameters
Evaluate the difference between struct and class by assigning initial values to type members
If the field is assigned an initial value directly.
public struct SizeStruct { public int _length = 10; }
Run, error: the structure cannot contain the instance field Initial Value Setting item
If an initial value is assigned to a field through the constructor.
public struct SizeStruct { public int _length; public SizeStruct() { _length = 10; } }
Run, error: the structure cannot contain explicit non-parameter Constructor
It can be seen that it is not easy to assign an initial value to a struct type member, but assign an initial value to a class member, no problem.
When to use struct and class?
In most cases, we recommend that you use a class because, whether it is a class assignment, passing as a parameter type, or returning an instance of the class, the actual copy is the reference address on the hosting stack, it is about 4 bytes, which is very helpful for performance improvement.
As a struct type, whether it is a value assignment, passed as a parameter type, or returns a struct type instance, it is a full copy, it will occupy the space on the stack. Based on Microsoft's Value Type Recommendations, struct is recommended in the following cases:
● Less than 16 bytes
● Value-oriented, simple data, rather than "Object-Oriented"
● The expected value is unchangeable
References:
C # Fundamentals: The Differences Between Struct and Class
Difference between class and struct in C #. Net
Difference Between Class and Structure
C language rand () function
Rand and srand usage
First, we need to have a general opinion on rand & srand: srand initializes random seeds, and rand generates random numbers. The following describes in detail.
Rand (Random Number Generation)
Header file: # include <stdlib. h>
Define function: int rand (void)
Function Description:
Because the internal implementation of rand is made by the linear same remainder method, it is not a real random number, but because its cycle is very long, so it can be considered as random within a certain range, rand () returns a random value ranging from 0 to RAND_MAX. Before calling this function to generate a random number, you must use srand () to set the random number seed. If no random number seed is set, rand () will automatically set the random number seed to 1. Rand () generates false random numbers, which are the same during each execution. To be different, initialize it with different values. The initialized function is srand ().
Return Value:
Returns a random integer between 0 and RAND_MAX. The range of RAND_MAX is at least 32767 (int), that is, double byte (16 digits ). If unsigned int is used, the dual-byte value is 65535, and the four-byte value is an integer range of 4294967295.
0 ~ RAND_MAX the probability of each number being selected is the same.
Example:
/* Generate a random value ranging from 1 to 10. In this example, no random seed is set. For the complete random number generation, see
Srand ()*/
# Include <stdlib. h>
Main ()
{
Int I, j;
For (I = 0; I <10; I ++)
{
J = 1 + (int) (10.0 * rand ()/(RAND_MAX + 1.0 ));
Printf ("% d", j );
}
}
Run:
9 4 8 8 10 2 4 8 3 6
9 4 8 8 10 2 4 8 3 6 // re-execution still produces the same random number
Srand (set Random Seed)
Header file: # include <stdlib. h>
Define the function: void srand (unsigned int seed );
Function Description:
Srand () is used to set the random number seed when rand () generates a random number. The seed parameter must be an integer. Generally, the return value of geypid () or time (0) can be used as seed. If the same value is set for each seed, the random values generated by rand () are the same each time.
Example
/* Generate a random number ranging from 1 to 10. This example and execution result can be referenced with rand */
# Include <time. h>
# Include <stdlib. h>
Main ()
{
Int I, j;
Srand (int) time (0 ));
For (I = 0; I <10; I ++)
{
J = 1 + (int) (10.0 * rand ()/(RAND_MAX + 1.0 ));
Printf ("% d", j );
}
}
Execution: Compare with the rand example
5 8 8 8 10 2 10 8 9 9
2 9 7 4 10 3 2 10 8 7
Or:
Use "int x = rand () % 100;" to generate a random number between 0 and 100. This method is not or can be used. A better method is j = (int) (n * rand ()/(RAND_MAX + 1.0) generates a random number between 0 and n.
Int main (void)
{
Int I;
Time_t t;
Srand (unsigned) time (& t ));
Printf ("Ten r... the remaining full text>
C language rand () function
Rand and srand usage
First, we need to have a general opinion on rand & srand: srand initializes random seeds, and rand generates random numbers. The following describes in detail.
Rand (Random Number Generation)
Header file: # include <stdlib. h>
Define function: int rand (void)
Function Description:
Because the internal implementation of rand is made by the linear same remainder method, it is not a real random number, but because its cycle is very long, so it can be considered as random within a certain range, rand () returns a random value ranging from 0 to RAND_MAX. Before calling this function to generate a random number, you must use srand () to set the random number seed. If no random number seed is set, rand () will automatically set the random number seed to 1. Rand () generates false random numbers, which are the same during each execution. To be different, initialize it with different values. The initialized function is srand ().
Return Value:
Returns a random integer between 0 and RAND_MAX. The range of RAND_MAX is at least 32767 (int), that is, double byte (16 digits ). If unsigned int is used, the dual-byte value is 65535, and the four-byte value is an integer range of 4294967295.
0 ~ RAND_MAX the probability of each number being selected is the same.
Example:
/* Generate a random value ranging from 1 to 10. In this example, no random seed is set. For the complete random number generation, see
Srand ()*/
# Include <stdlib. h>
Main ()
{
Int I, j;
For (I = 0; I <10; I ++)
{
J = 1 + (int) (10.0 * rand ()/(RAND_MAX + 1.0 ));
Printf ("% d", j );
}
}
Run:
9 4 8 8 10 2 4 8 3 6
9 4 8 8 10 2 4 8 3 6 // re-execution still produces the same random number
Srand (set Random Seed)
Header file: # include <stdlib. h>
Define the function: void srand (unsigned int seed );
Function Description:
Srand () is used to set the random number seed when rand () generates a random number. The seed parameter must be an integer. Generally, the return value of geypid () or time (0) can be used as seed. If the same value is set for each seed, the random values generated by rand () are the same each time.
Example
/* Generate a random number ranging from 1 to 10. This example and execution result can be referenced with rand */
# Include <time. h>
# Include <stdlib. h>
Main ()
{
Int I, j;
Srand (int) time (0 ));
For (I = 0; I <10; I ++)
{
J = 1 + (int) (10.0 * rand ()/(RAND_MAX + 1.0 ));
Printf ("% d", j );
}
}
Execution: Compare with the rand example
5 8 8 8 10 2 10 8 9 9
2 9 7 4 10 3 2 10 8 7
Or:
Use "int x = rand () % 100;" to generate a random number between 0 and 100. This method is not or can be used. A better method is j = (int) (n * rand ()/(RAND_MAX + 1.0) generates a random number between 0 and n.
Int main (void)
{
Int I;
Time_t t;
Srand (unsigned) time (& t ));
Printf ("Ten r... the remaining full text>