Language-specific · 36
Structs
Bundle related values into one unit, and know whether that unit is copied or shared.
This lesson is for C# · C++ · C.
Python, JavaScript, TypeScript and Java group data with classes and objects (see the classes lesson), and Craykon uses 사전() dictionaries.
In all of them assignment shares the same object through a reference, unlike a struct, which is copied.
Values that always travel together, like a point's x and y or a student's name and score, are grouped into a struct.
The example below copies a point, changes only the copy, then moves the original, to show how copy and original differ.
using System; struct Point // 값 타입: class로 바꾸면 q = p 가 같은 객체를 가리켜요{ public int X, Y; public void Move(int dx, int dy) { X += dx; Y += dy; } public int Len2() => X * X + Y * Y; public override string ToString() => $"({X}, {Y})";} class Program{ static void Main() { string[] t = Console.ReadLine().Split(); var p = new Point { X = int.Parse(t[0]), Y = int.Parse(t[1]) }; Console.WriteLine($"p = {p}"); Point q = p; // 데이터가 복사돼요 q.X = 10; Console.WriteLine($"q = {q}"); Console.WriteLine($"p = {p}"); p.Move(1, 1); Console.WriteLine($"p = {p}"); Console.WriteLine($"len2 = {p.Len2()}"); }}#include <iostream>#include <string> struct Point { int x = 0, y = 0; void move(int dx, int dy) { x += dx; y += dy; } // 멤버 함수 int len2() const { return x * x + y * y; } // 바꾸지 않으면 const}; void print(const std::string& name, const Point& p) { std::cout << name << " = (" << p.x << ", " << p.y << ")\n";} int main() { Point p; std::cin >> p.x >> p.y; print("p", p); Point q = p; // 멤버가 통째로 복사돼요 q.x = 10; print("q", q); print("p", p); p.move(1, 1); print("p", p); std::cout << "len2 = " << p.len2() << '\n';}#include <stdio.h> typedef struct { int x, y;} Point; void print_point(const char *name, Point p) { printf("%s = (%d, %d)\n", name, p.x, p.y);} void move(Point *p, int dx, int dy) { /* 원본을 바꾸려면 포인터로 */ p->x += dx; p->y += dy;} int len2(Point p) { /* 읽기만 하니 값으로 받아도 돼요 */ return p.x * p.x + p.y * p.y;} int main(void) { Point p; scanf("%d %d", &p.x, &p.y); print_point("p", p); Point q = p; /* 멤버가 통째로 복사돼요 */ q.x = 10; print_point("q", q); print_point("p", p); move(&p, 1, 1); print_point("p", p); printf("len2 = %d\n", len2(p)); return 0;}3 4
p = (3, 4) q = (10, 4) p = (3, 4) p = (4, 5) len2 = 41
Key points
- One bundle becomes a new type.
You can pass it, return it and store it in an array as a single variable. - The values inside are members (fields), read with a dot like
p.x. - Assigning a struct or passing it to a function copies every member.
So afterq = pandq.x = 10,pis still(3, 4). - To change the original, pass a pointer or a reference.
Big structs are expensive to copy, so they are often passed byconstpointer or reference even when only read.
How each language writes it
| C# | A struct is a value type, so Point q = p; copies the data; a class is a reference type, so the same assignment points at the same object (make the example class Point and after q.X = 10, p is (10, 4) too) — int, double and DateTime are structs.Use struct for small values like coordinates, colours and dates (readonly struct or record struct to make them immutable), and class otherwise.Pass the original with ref |
|---|---|
| C++ | Just Point, no typedef.A struct can hold member functions ( void move(int dx, int dy)), and ones that don't modify get const, like int len2() const — struct and class differ only in default access (public for struct, private for class).Pass the original as Point& or const Point& |
| C | struct Point { int x, y; }; needs struct Point p; every time, so people usually write typedef struct { int x, y; } Point; — change the original with move(&p, 1, 1), reach members through a pointer with p->x instead of (*p).x, and use const Point * when only reading |
Common mistakes
Changing a member of a struct in a listC#
var list = new List<Point> { new Point() };
list[0].X = 5;→ Compile error CS1612: the indexer returns a copy. arr[0].X = 5 on an array works, but a struct taken out by foreach can't be changed either (CS1654)
Take the copy out, change it, and put it back: var t = list[0]; t.X = 5; list[0] = t;
Comparing structs with ==
if (p == q) { … }→ A compile error in C. In C++ without an operator==, and for a C# struct that doesn't define == (CS0019), it is a compile error too
In C, compare member by member (memcmp can be wrong because of padding bytes between members).
C++20 can write bool operator==(const Point&) const = default;; in C#, p.Equals(q) compares member values, and record struct generates == as well.
Taking it by value moved only the copyC · C++
void move(Point p, int dx, int dy) {
p.x += dx;
p.y += dy;
}→ The caller's p doesn't change. No error, no warning
Take a Point * in C, or a Point& in C++.
Every time you pass or assign a struct, ask whether it is a copy or the same thing.
C, C++ and C#
structs are copied, so changing the original takes a pointer (Point *), a reference (Point&) or C# ref, while a C# class shares one object.