Programming Language (Programming Language) is a bridge between people and computers. It is used to write instructions, control computer operations and implement various applications.
According to the latest programming language rankings, here are the top 20 programming languages in 2024:
A lambda expression is an anonymous function that is often used to simplify code, especially when you need to pass small functions or callbacks. The syntax of Lambda expression is concise and function logic can be defined in one line. Lambda expressions are most commonly found in Languages such as C++, JavaScript, Python and C#.
The basic syntax of lambda expressions usually includes parameters, arrow symbols=>and function body, for example:
(parameter) => function body
The exact syntax varies from language to language, for example:
[capture](parameters) { function body }lambda parameters: expression(parameters) => expression
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vectornumbers = {1, 2, 3, 4, 5};
// Use lambda expression to calculate the sum of even numbers
int sum = 0;
std::for_each(numbers.begin(), numbers.end(), [&sum](int n) {
if (n % 2 == 0) sum += n;
});
std::cout << "The sum of even numbers: " << sum << std::endl;
return 0;
}
# Use lambda expression to calculate the sum of two numbers
add = lambda x, y: x + y
print(add(5, 10)) # Output: 15
using System;
using System.Collections.Generic;
using System.Linq;
class Program {
static void Main() {
List numbers = new List{ 1, 2, 3, 4, 5 };
// Use a Lambda expression to filter out even numbers and calculate the sum
int sum = numbers.Where(n => n % 2 == 0).Sum();
Console.WriteLine($"The sum of even numbers: {sum}");
}
}
map、filterandreduceWait for higher-order functions to operate on collections.# Python: List and read object properties
class User:
def __init__(self): self.id = 0; self.name = "Ann"
u = User()
for k, v in vars(u).items():
print(k, v) # id 0 / name Ann
// C#: Get the field/property and read the value
using System;
using System.Reflection;
var t = typeof(MyType);
foreach (var p in t.GetProperties(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic))
Console.WriteLine($"{p.Name}={p.GetValue(obj)}");
// JavaScript: dynamic enumeration and calling
const obj = { x: 1, y: 2, add(){ return this.x + this.y; } };
for (const [k,v] of Object.entries(obj)) console.log(k, v);
console.log(obj["add"]()); // 3
// Java: Reading/writing fields using reflection
import java.lang.reflect.*;
class U { private int id = 42; }
U u = new U();
Field f = U.class.getDeclaredField("id");
f.setAccessible(true);
System.out.println(f.getInt(u)); // 42
// Go: reflect visit structure
import "reflect"
func Dump(v any) {
val := reflect.ValueOf(v)
for i := 0; i < val.NumField(); i++ {
name := val.Type().Field(i).Name
fmt.Println(name, val.Field(i).Interface())
}
}
| language | Support | illustrate |
|---|---|---|
| Python | ✅ | Dynamic, full reflection, easy recursive object/container inspection. |
| JavaScript / TypeScript | ✅ | The object is key-value and availableObject.valuesrecursion. |
| Ruby | ✅ | instance_variablesreflective member. |
| PHP | ✅ | get_object_vars()Or Reflection. |
| C# (.NET) | ✅ | Reflection obtains fields/properties and has good type safety. |
| Java | ✅ | java.lang.reflectScannable fields. |
| Kotlin | ✅ | JVM reflection is complete, similar to Java. |
| Go | ✅ | reflectAccessible to struct fields. |
| Swift | ◑ | MirrorVisits are possible, but the scenes are limited and additional processing is required. |
| C++ (to C++23) | ❌ | No runtime reflection, you need to manually write checks for types. |
| Rust | ❌ | No runtime reflection, often implemented by derive/trait. |
def is_all_zero(obj, eps=1e-6):
if isinstance(obj, (int, float)): # Basic numerical value
return abs(obj) < eps
elif isinstance(obj, (list, tuple, set)): # sequence/set
return all(is_all_zero(x, eps) for x in obj)
elif isinstance(obj, dict): # Dictionary
return all(is_all_zero(v, eps) for v in obj.values())
elif hasattr(obj, "__dict__"): # General objects
return all(is_all_zero(v, eps) for v in vars(obj).values())
else:
return False
# test
class point:
def __init__(self, x=0, y=0): self.x, self.y = x, y
class Line:
def __init__(self, p1=None, p2=None):
self.p1 = p1 or Point()
self.p2 = p2 or Point()
print(is_all_zero([[0,0],[0,0]])) # True
print(is_all_zero(Line(Point(0,0),Point(0,0)))) # True
print(is_all_zero(Line(Point(1,0),Point(0,0)))) # False
function isAllZero(obj, eps = 1e-6) {
const isNumZero = n => Math.abs(n) < eps;
if (typeof obj === "number") return isNumZero(obj);
if (Array.isArray(obj)) return obj.every(v => isAllZero(v, eps));
if (obj && typeof obj === "object")
return Object.values(obj).every(v => isAllZero(v, eps));
return false;
}
console.log(isAllZero([[0,0],[0,0]])); // true
console.log(isAllZero({x:0, y:{z:0}})); // true
console.log(isAllZero({x:0.000001, y:0})); // depends on eps
using System;
using System.Linq;
using System.Reflection;
public static class ZeroCheck {
public static bool IsAllZero(object obj, double eps = 1e-6) {
if (obj == null) return true;
switch (obj) {
case int i: return i == 0;
case long l: return l == 0;
case float f: return Math.Abs(f) < eps;
case double d: return Math.Abs(d) < eps;
}
var t = obj.GetType();
if (t.IsArray)
return ((Array)obj).Cast<object>().All(x => IsAllZero(x, eps));
//Scan fields and attributes
foreach (var f in t.GetFields(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic))
if (!IsAllZero(f.GetValue(obj), eps)) return false;
foreach (var p in t.GetProperties(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic))
if (p.CanRead && !IsAllZero(p.GetValue(obj, null), eps)) return false;
return true;
}
}
package main
import (
"math"
"reflect"
)
func IsAllZero(v interface{}, eps float64) bool {
val := reflect.ValueOf(v)
switch val.Kind() {
case reflect.Float32, reflect.Float64:
return math.Abs(val.Float()) < eps
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return val.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return val.Uint() == 0
case reflect.Slice, reflect.Array:
for i := 0; i < val.Len(); i++ {
if !IsAllZero(val.Index(i).Interface(), eps) { return false }
}
return true
case reflect.Map:
for _, k := range val.MapKeys() {
if !IsAllZero(val.MapIndex(k).Interface(), eps) { return false }
}
return true
case reflect.Struct:
for i := 0; i < val.NumField(); i++ {
if !IsAllZero(val.Field(i).Interface(), eps) { return false }
}
return true
case reflect.Pointer, reflect.Interface:
if val.IsNil() { return true }
return IsAllZero(val.Elem().Interface(), eps)
default:
return false
}
}
isAllZero, or use template/macro to help expand members.deriveMacros automatically generate implementations for types (such as custom traitsIsAllZero)。eps, to avoid accuracy issues leading to misjudgments.isAllZero()method to avoid costly reflection scans.Message Queue (MQ) is an architectural pattern for asynchronous communication between software systems. It allows independent applications or services to exchange information by sending and receiving messages without having to call each other directly or rely on each other's real-time status. The core role of MQ is to act as a middle layer that temporarily stores messages until the intended recipient is ready to process them.
| Schema name | describe | Typical application scenarios |
|---|---|---|
| Point-to-Point (P2P) | A message is sent to a queue, and **only one** recipient will take it out of the queue and consume the message. Once consumed, the message is deleted. | Order processing, task dispatch, and workload balancing. |
| Publish/Subscribe, Pub/Sub | A message is published to a topic, and **all** recipients (Subscribers) subscribed to the topic will receive a copy of the message. | System event broadcast, log collection, data change notification. |
Message queues are the cornerstone of modern distributed systems, microservices architectures, and high-availability applications. It significantly improves the system's resilience, scalability, and robustness by introducing indirection in time and space.
| characteristic | Message Queue (MQ) | HTTP API (REST/RPC) |
|---|---|---|
| Communication type | Asynchronous | Synchronous |
| Coupling | Low coupling (the sender and receiver do not interact directly) | High coupling (the client needs to know the server's address and wait for a reply) |
| data flow | One-way, passed through the intermediate Broker | Two-way, request and response (Request-Response) |
| fault tolerance | High, the Broker stores the message and the message will not be lost even if the recipient is offline. | Low, the server is offline or times out, causing the request to fail. |
| Scalability | High, multiple consumers can be easily added to handle the load | Relatively low, relying on load balancer to distribute requests |
MQ and HTTP API are not replacement technologies, but are designed for different problems.
In modern distributed systems, the two modes often coexist and cooperate with each other to meet different business needs.
In many network applications, some operations are time-consuming, and if users are made to wait simultaneously, it will result in a poor user experience. MQ allows these tasks to be executed asynchronously.
MQ is critical in handling transient high-traffic scenarios and can protect backend services from crashing.
In complex distributed systems and microservice architectures, MQ is used to isolate services and reduce interdependence.
Collect large amounts of log data from front-end applications or servers into a centralized processing system.
In particular, high-throughput MQ/streaming platforms like Apache Kafka are ideal for handling continuous streams of real-time data.
The main challenges in using HTTP API to transfer large binary data (Binary Data) such as images and videos are:
This is the most standard and common way for a browser or client application to upload files.
multipart/form-data; boundary=YourBoundaryString
If you only need to upload a single file, you can directly use the binary content of the file as the subject of the request.
image/jpegorimage/png;video:video/mp4。
Convert binary data into ASCII strings and embed them into text formats such as JSON or XML for transmission.
Content-Type, APIs for handling simple text formats are also supported.Downloading binary data is relatively simple. The server directly returns the original binary content of the file as the body of the HTTP response (Response Body).
image/jpegorvideo/mp4。
attachment; filename="example.mp4", instructs the browser to download the content as a file rather than display it directly.For particularly large files (especially videos), the following techniques are recommended to improve reliability and efficiency:
RangeRequest a specific fragment of an archive (e.g.Range: bytes=100-200). This is very important for video streaming (Streaming), allowing the player to download only the part that needs to be played, and supports fast forward/rewind.The core of streaming transmission lies in how to transmit audio and video content from the server to the client efficiently, stably and with low latency.
This is the cornerstone of modern streaming services. The server will encode the same piece of video content into multiple versions of different qualities (bit rate, resolution).
CDN is indispensable for streaming services targeting global users.
Used to compress and decompress audio and video data to reduce file size.
In Bash, $? represents the exit status code (Exit Status) of the last executed command. This is an integer value usually used to determine whether the previous command was executed successfully.
#!/bin/bash
ls
echo "The exit status code of the previous command was: $?"
In this example,lsThe command will list the directory contents. After successful execution,$?The value will be 0.
#!/bin/bash
ls /nonexistent-directory
echo "The exit status code of the previous command was: $?"
In this example,lsAttempting to list a directory that does not exist will cause the command to fail.$?The value of will be a non-zero number.
#!/bin/bash
cp file1.txt /some/directory/
if [ $? -eq 0 ]; then
echo "File copied successfully."
else
echo "File copy failed."
fi
This example determines which message to display based on the exit status of the command.
if [condition]; then
instructions
fi
To satisfy multiple conditions simultaneously in if , use:
-a(outdated but available)if [ "$a" -gt 0 -a "$b" -gt 0 ]; then
echo "a and b are both greater than 0"
fi
[[ ]] &&(recommend)if [[ "$a" -gt 0 && "$b" -gt 0 ]]; then
echo "a and b are both greater than 0"
fi
&&if [ "$a" -gt 0 ] && [ "$b" -gt 0 ]; then
echo "a and b are both greater than 0"
fi
It can be executed as long as one of the conditions is true:
-o(outdated but available)if [ "$a" -eq 0 -o "$b" -eq 0 ]; then
echo "a or b is 0"
fi
[[ ]] ||(recommend)if [[ "$a" -eq 0 || "$b" -eq 0 ]]; then
echo "a or b is 0"
fi
||if [ "$a" -eq 0 ] || [ "$b" -eq 0 ]; then
echo "a or b is 0"
fi
Can be used with parentheses to control precedence:
if [[ ( "$a" -gt 0 && "$b" -gt 0 ) || "$c" -eq 1 ]]; then
echo "a and b are both greater than 0, or c is equal to 1"
fi
In Bash,ifInstructions are usually paired with[ ](test command) or[[ ]](Extended Test Command) is used. To express NOT, use an exclamation point!。
if [ ! condition ]; then
# Code to be executed when the condition is false
fi
This is the most common usage, for example: create a file if it "doesn't exist".
# If no file named config.txt exists
if [ ! -f "config.txt" ]; then
echo "File does not exist, creating..."
touch config.txt
fi
# If the directory does not exist
if [ ! -d "/var/log/myapp" ]; then
mkdir -p "/var/log/myapp"
fi
Check whether the string is "not equal to" or "not empty".
STR="hello"
# Check if the variable is not equal to "world"
if [ "$STR" != "world" ]; then
echo "String does not match"
fi
# Check if the string is not empty (! -z is equivalent to -n)
if [ ! -z "$STR" ]; then
echo "There is data in the variable"
fi
Although the numerical value is relatively-ne(not equal), but can also be matched!use.
NUM=10
if [ ! "$NUM" -eq 20 ]; then
echo "The number is not equal to 20"
fi
| operator | illustrate | example |
|---|---|---|
! -f |
File does not exist | [ ! -f file ] |
! -d |
Directory does not exist | [ ! -d dir ] |
!= |
String is not equal to | [ "$a" != "$b" ] |
! -z |
String is not empty | [ ! -z "$str" ] |
-ne |
Value is not equal to | [ "$n" -ne 5 ] |
In more modern Bash scripts, it is recommended to use[[ ]], which is processing!More powerful and less error-prone when combined with logic.
# Combine multiple conditions: if it is not a directory and cannot be read
if [[ ! -d $path && ! -r $path ]]; then
echo "Invalid path or insufficient permissions"
fi
[[ ]]timely support&&and||[ ]It is recommended to use multiple conditional statements together&& / ||caseStatement is used to compare the value of a variable with multiple patterns (patterns), and its function is similar to that in other languages.switch. Its grammatical structure is as follows:
case variable in
Mode 1)
# Execute instructions
;;
Mode 2)
# Execute instructions
;;
*)
# Default execution command (similar to default)
;;
esac
This is the most common usage, performing different actions based on user input.
read -p "Please enter (yes/no): " input
case "$input" in
"yes")
echo "You selected Yes"
;;
"no")
echo "Did you choose No"
;;
*)
echo "Input error"
;;
esac
use|Symbols allow multiple modes to execute the same block of instructions.
read -p "Please enter the month abbreviation: " month
case "$month" in
Jan|Feb|Mar)
echo "Season 1"
;;
Apr|May|Jun)
echo "Season 2"
;;
*)
echo "other months"
;;
esac
Pattern matching supports extended symbols like file paths (e.g.*, ?, [a-z])。
read -p "Please enter a character: " char
case "$char" in
[a-z])
echo "This is lowercase letter"
;;
[A-Z])
echo "This is a capital letter"
;;
[0-9])
echo "This is a number"
;;
*)
echo "This is a special symbol or multiple characters"
;;
esac
| symbol | Function description |
|---|---|
) |
The end tag of the pattern. |
;; |
The end marker of the instruction block (similar tobreak)。 |
* |
Compares any string, usually placed last as the default option. |
| |
Used to separate multiple matching patterns (representing "or"). |
esac |
caseSpelled backwards, it represents the end of the grammar block. |
"$var") to avoid syntax errors when the variable has a null value.casewill be compared from top to bottom. Once the match is successful and encounter;;will stop, so please put the specific mode in the general mode (such as*)Before.Default behavior: case sensitive. In a standard Bash environment,caseThe statement isCase sensitiveof. This means "A" and "a" are treated as different patterns.
read -p "Enter a character: " char
case "$char" in
a) echo "This is lowercase a" ;;
A) echo "This is capital A" ;;
esac
---
If you want the entirecaseThe statement ignores case and can be usedshoptcommand enablednocasematchset up. This will affect all subsequent string comparisons andcasejudge.
# Enable ignoring case
shopt -s nocasematch
read -p "Enter yes or YES: " input
case "$input" in
yes) echo "Match successful (ignore case)" ;;
esac
# Turn off ignoring case (restore default)
shopt -u nocasematch
---
If you don't want to change the global setting, defining the case range directly in the schema is the most standard and consistent approach.
read -p "Enter a letter: " char
case "$char" in
[aA])
echo "You entered a or A"
;;
[b-zB-Z])
echo "You entered additional letters"
;;
esac
---
For specific words, you can use|to list all possible spellings.
case "$input" in
stop|STOP|Stop)
echo "stop execution"
;;
esac
---
| method | advantage | shortcoming |
|---|---|---|
shopt -s nocasematch |
The program code is concise and suitable for large-scale comparisons. | It will affect the behavior of the entire script, so remember to turn it off manually. |
[a-zA-Z]scope |
Precise control without affecting other parts. | If the words are very long, writing will become very cumbersome. |
pipe character| |
High readability, suitable for a specific few words. | Cannot handle random case combinations (such as YeS). |
Arithmetic extensions in Bash(( ))Internally, you can just use parentheses( )to explicitly specify the precedence of operations, consistent with the logic of C or most programming languages. This is very important when dealing with complex logic (combining AND, OR, addition, subtraction, multiplication and division).
# Example: (A and B) or C
if (( (MIN > 91 && MIN< 110) || FORCE_MODE == 1 )); then
echo "條件成立"
fi
exist(( ))Within, the order of precedence of operations follows standard mathematical and logical conventions:
( )Highest priority.*, /, %。+, -。<, >, <=, >=。&&(AND) takes precedence over|| (OR)。Suppose you need to determine: the value must be within the range, and (must be a specific multiple or in forced mode):
if (( MIN > 91 && (MIN % 5 == 0 || FORCE_MODE == 1) )); then
{
echo "Trigger complex conditional judgment"
IS_SHUTDOWN=true
} |& tee -a "$LOGFILE"
fi
| syntax type | Grouping symbol | Things to note |
|---|---|---|
(( ... )) |
( ) |
The most intuitive, symbols do not need to be escaped, and are recommended for pure numerical operations. |
[[ ... ]] |
( ) |
exist[[ ]]It is also legal to use parentheses within for logical grouping. |
[ ... ] |
\( ... \) |
TraditiontestSyntax, brackets must be escaped with backslashes, which is not recommended. |
In a Bash script,exitUsed to terminate script execution and return a status code (Exit Status) to the parent program.
if [ -f "config.txt" ]; then
echo "File exists"
exit 0
else
echo "Error: Profile not found"
exit 1
fi
After executing a script or instruction, you can use special variables$?to get the previous programexitstatus code.
./script.sh
echo "Script end status: $?"
when you call.shfile and want to "output the contents" of it (i.e.echoWhen storing the contents of a variable, you can use backticks or$(). This is called Command Substitution.
#!/bin/bash
# This is the output content and will be captured
echo "Ubuntu_User"
# This is the end state and will not be captured by backticks
exit 0
# Use backticks
RESULT=`./get_name.sh`
# Use $() (recommended modern writing)
RESULT=$(./get_name.sh)
echo "The result obtained is: $RESULT"
| Target | How to obtain | use |
|---|---|---|
| Exit Status (status code) | $? |
Determine whether the instruction execution was successful (0 or 1). |
| Standard Output (output content) | ` `or$( ) |
Get the string data generated after the script is executed. |
If you want to get both at the same time, you can refer to the following example:
OUTPUT=$(./script.sh)
STATUS=$?
echo "Content is: $OUTPUT"
echo "The status code is: $STATUS"
In Bash,returninstructions are specifically used toFunctionor throughsourceThe script to execute. It stops execution of the current function or script and returns the specified status code to the caller, but does not close the current shell program.
This is the most common usage.returnWhat is returned is the status code (0-255), not the string data.
#!/bin/bash
# define function
check_file() {
if [ -f "$1" ]; then
return 0 # success
else
return 1 # failed
fi
}
# Call function
check_file "test.txt"
RESULT=$?
if [ $RESULT -eq 0 ]; then
echo "File exists"
else
echo "File does not exist"
fi
If you want the variables and environment to remain in the current terminal after a script is executed, you usually usesource. Must be used at this timereturnrather thanexit。
# Simulate logical judgment
if [ "$USER" != "root" ]; then
echo "Insufficient permissions, only for root use"
# If you use exit, you will directly close the terminal. If you use return, you will only stop the execution of this script.
return 1
fi
export APP_STATUS="Ready"
return 0
source ./sub_script.sh
echo "Script returns status: $?"
echo "Get environment variables: $APP_STATUS"
becausereturnOnly numbers (status codes) can be returned. To obtain strings or large amounts of data, it is recommended to combineechoandcommand substitution。
#!/bin/bash
calculate() {
local val=$(( $1 + $2 ))
# Output results to stdout
echo "$val"
# Return execution status code
return 0
}
calculate 10 20
# Get the output content
DATA=$(./get_data.sh)
# Get the status code of return
STATUS=$?
echo "The calculation result is: $DATA"
echo "Execution status: $STATUS"
| Keywords | Scope of application | Impact on the main program |
|---|---|---|
exit 0/1 |
Independent scripts and subroutines | Will terminate the entire current Shell (if executed with source). |
return 0/1 |
Function, source script loaded | Only exits the current scope and does not affect the main program Shell. |
echo "..." |
anywhere | Used to pass the actual "data content" to the caller. |
In Bash, you can use conditional judgment to check whether a variable is empty. Here are several common ways:
-zCheck if variable is empty#!/bin/bash
var=""
if [ -z "$var" ]; then
echo "The variable is empty"
else
echo "The variable is not empty"
fi
-zUsed to check whether the variable is empty. If the variable is empty, the condition is true.
-nCheck if the variable is not empty#!/bin/bash
var="some value"
if [ -n "$var" ]; then
echo "The variable is not empty"
else
echo "The variable is empty"
fi
-nUsed to check whether the variable is not empty. If the variable has a value, the condition is true.
#!/bin/bash
var=""
if [ "$var" == "" ]; then
echo "The variable is empty"
else
echo "The variable is not empty"
fi
This method directly compares the variable with the empty string to check whether the variable is empty.
Bash supports two types of arrays:
fruits=("apple" "banana" "cherry")
echo "${fruits[0]}" # apple
echo "${fruits[1]}" # banana
echo "${fruits[@]}"
echo "${#fruits[@]}"
fruits+=("date")
for fruit in "${fruits[@]}"; do
echo "$fruit"
done
declare -A capital
capital["Taiwan"]="Taipei"
capital["Japan"]="Tokyo"
echo "${capital["Japan"]}" # Tokyo
for key in "${!capital[@]}"; do
echo "The capital of $key is ${capital[$key]}"
done
declare -AdeclareBash array is an important structure for storing multiple pieces of data, and is suitable for data processing such as parameter lists, directory sets, and key-value pairs.
combined=("${array1[@]}" "${array2[@]}")
This will merge all elements from both arrays into a new arraycombined。
array1=("apple" "banana")
array2=("cherry" "date")
combined=("${array1[@]}" "${array2[@]}")
echo "Combined array:"
for item in "${combined[@]}"; do
echo "$item"
done
array1+=("${array2[@]}")
This willarray2content is added directly toarray1rear.
"${array[@]}"form to prevent elements from being expanded incorrectlystr="hello world"
if [[ "$str" == hello* ]]; then
echo "String starts with hello"
fi
illustrate:use[[ ]]Support shell pattern comparison,*Represents any character.
if [[ "$str" =~ ^hello ]]; then
echo "String starts with hello"
fi
illustrate: ^Indicates the beginning,[[ ]]in=~is a regular operation.
caseNarratecase "$str" in
hello*) echo "String starting with hello" ;;
*) echo "does not start with hello" ;;
esac
illustrate: caseIt is a good tool for processing string patterns, concise and highly readable.
expr(Old style of writing)if expr "$str" : '^hello' &> /dev/null; then
echo "String starts with hello"
fi
illustrate:useexprRegular matching function, suitable for older versions of the shell.
[[ ]]Compare[ ]More complete functions, recommended to use=~Regular expressions can be used, but remember not to add quotes-e-eUsed to check whether a file or directory exists (regardless of type).
FILE="/etc/passwd"
if [ -e "$FILE" ]; then
echo "$FILE exists"
else
echo "$FILE does not exist"
fi
! -d-dUsed to check whether it is a directory,!It is a negative operation.
DIR="/tmp/myfolder"
if [ ! -d "$DIR" ]; then
echo "$DIR does not exist, creating..."
mkdir -p "$DIR"
else
echo "$DIR already exists"
fi
-e: Whether the file or directory exists (no matter what type)-f: Whether it is a "general file"-d: Whether it is a "directory"-L: Whether it is a "symbolic link"PATH_TO_CHECK="/home/user/config"
if [ -e "$PATH_TO_CHECK" ]; then
echo "$PATH_TO_CHECK already exists"
else
echo "$PATH_TO_CHECK does not exist and is being created..."
mkdir -p "$PATH_TO_CHECK"
fi
-e-dor-ftarget_dir="/path/to/your/dir"
subdirs=()
while IFS= read -r -d $'\0' dir; do
subdirs+=("$dir")
done < <(find "$target_dir" -mindepth 1 -maxdepth 1 -type d -print0)
find: List subdirectories (no recursion)-mindepth 1:Exclude own directory-maxdepth 1:Only list the first level-type d:Only list directories-print0matchread -d $'\0': Handle paths with spacesfor dir in "${subdirs[@]}"; do
echo "$dir"
done
subdirs=( "$target_dir"/*/ )
This way of writing uses wildcards to match subdirectories, but it cannot exclude files or handle spaces and special characters.
path="~/myfolder/file.txt"
realpath "$(eval echo "$path")"
path="~/myfolder/file.txt"
realpath "$(echo "$path" | sed "s|^~|$HOME|")"
path="~/myfolder/file.txt"
readlink -f "$(eval echo "$path")"
realpath "$(eval echo "$path")"
grep "keyword" file name
grep -i "keyword" file name
grep -n "keyword" file name
grep -r "keyword" directory path
grep -o "keyword" file name
grep -H "keyword" file name
grep "keyword 1" file name | grep "keyword 2"
#Method 1: Regular expression
grep -E "Keyword 1 | Keyword 2" file name
#Method 2: Multiple -e parameters
grep -e "keyword 1" -e "keyword 2" file name
#Method 1: Force the file to be treated as text
grep -a "keyword" file name
#Method 2: Convert the file encoding to UTF-8 and then search
iconv -f original encoding -t UTF-8 file name | grep "keyword"
# Example (convert from BIG5 to UTF-8)
iconv -f BIG5 -t UTF-8 file name | grep "keyword"
grep -rin "keyword" directory path
When processing file names or paths that contain spaces or special symbols (such as blanks, quotation marks, newlines), the traditionalfindDistribution linexargsorreadMisjudgment may occur.
-print0Allowablefindwith null(\0) characters as output delimiters, whileread -d $'\0'Can accurately read null-delimited content to ensure accurate separation of each file/path.
subdirs=()
while IFS= read -r -d $'\0' dir; do
subdirs+=("$dir")
done < <(find . -type d -print0)
-print0: End each result with a null character without line breaks.-d $'\0':readRead one null-terminated item at a timeIFS=: Prevent spaces from being treated as field separators-r: Avoid skipping characters during processingtxt_files=()
while IFS= read -r -d $'\0' file; do
txt_files+=("$file")
done < <(find "$(pwd)" -type f -name "*.txt" -print0)
find . -type f -print0 | while IFS= read -r -d $'\0' file; do
echo "Processing: $file"
# your_command "$file"
done
find . -type d -print0 | while IFS= read -r -d $'\0' dir; do
if [[ "$dir" == *" "* ]]; then
echo "Directory containing spaces: $dir"
fi
done
Traditional usage is as follows:
find . -type f | while read file; do ...
However, if the file name contains a newline, it will causereadWrong parsing, even multiple lines are misjudged as multiple files.
-print0andread -d $'\0'The safest way to handle any file name-0Waiting sceneThe following writing method is used in some Bash or Cygwin environments:Read only the first item:
while IFS= read -r -d $'\0' dir; do
subdirs+=("$dir")
done < <(find "$target_dir" -mindepth 1 -maxdepth 1 -type d -print0)
This is usually because `<(find ...)` 在某些系統(如 Cygwin)不是「真正的檔案描述符」,造成 `read` 無法持續讀取。
-print0subdirs=()
find "$target_dir" -mindepth 1 -maxdepth 1 -type d -print0 | while IFS= read -r -d $'\0' dir; do
subdirs+=("$dir")
done
**Note**: If you want `subdirs` to be available in the main program, this method is not suitable (because `while ... |` subshell cannot return the array)
mapfile -d '' -t subdirs < <(find "$target_dir" -mindepth 1 -maxdepth 1 -type d -print0)
mapfile(orreadarray) can correctly read null-separated strings into arrays.
This is the most reliable way to keep it in the main shell.
for dir in "${subdirs[@]}"; do
echo "Found directory: $dir"
done
mapfile -d '' -tis processing-print0The safest and most Bash-native wayvar="line1
line2
line3"
while IFS= read -r line; do
echo "Read: $line"
done <<< "$var"
IFS=Avoid trim whitespace-rAvoid escape characters from being parsed<<<is a here-string, treats the variable content as input to whileread -r first_line <<< "$var"
echo "First line: $first_line"
readarray -t lines <<< "$var"
for line in "${lines[@]}"; do
echo "$line"
done
find . -mindepth 1 -maxdepth 1 -type d -name "abc*" -printf "%T@ %p\n" | sort -nr | cut -d' ' -f2-
-mindepth 1 -maxdepth 1: Only list subdirectories under the current directory-name "abc*": Name starts with abc-printf "%T@ %p\n": Print out the modification time (timestamp) and directory namesort -nr: Sort by time value from new to oldcut -d' ' -f2-: Remove the timestamp and only display the path./abc_latest
./abc_old
./abc_2020
readarray -t abc_dirs << <(
find . -mindepth 1 -maxdepth 1 -type d -name "abc*" -printf "%T@ %p\n" |
sort -nr | cut -d' ' -f2-
)
for dir in "${abc_dirs[@]}"; do
echo "Found: $dir"
done
-printfExclusive function for GNU find, default in macOSfindNot supported, availablegfindsubstitute%T@Represents "last modification time (seconds)". If you need to create a time, additional tools are required.DIR="/mnt/usb"
if [ -w "$DIR" ]; then
echo "$DIR is writable"
else
echo "$DIR is not writable"
fi
-wTo check whether the directory has "write permission". However, if the directory itself is writable but the actual device is read-only (for example, mount is readonly), this method may not work.
DIR="/mnt/usb"
TESTFILE="$DIR/.write_test"
if touch "$TESTFILE" 2>/dev/null; then
echo "$DIR is writable"
rm "$TESTFILE"
else
echo "$DIR is not writable"
fi
This method is the most reliable and can detect the mount status or whether the physical device is actually writable.
mountInstruction to check whether the mount is read-onlyMNT="/mnt/usb"
if mount | grep "$MNT" | grep -q "(ro,"; then
echo "$MNT is mounted read-only"
else
echo "$MNT is a writable mount"
fi
This method needs to check whether the device is read-only (ro) method.
In the shell, use `>` to redirect a command's standard output (stdout) to a file or device. If the file already exists, the contents will be overwritten.
echo "Hello" > output.txt
This line of instruction will"Hello"writeoutput.txtfile.
Using `>>` will append standard output to the end of the specified file without overwriting the original content.
echo "Hello again" >> output.txt
This line of command will"Hello again"append tooutput.txtthe end of.
In the shell, `2>` is used to redirect standard error (stderr) to a specified location. For example:
ls non_existent_file 2> error.log
This line of command will write the error message toerror.logfile.
If you do not want to overwrite the error message file, you can use `2>>` to append the error message to the end of the file.
ls non_existent_file 2>> error.log
This line of command will append the error message toerror.log。
Use `&>` to redirect both standard output and standard error to the same file or device.
command &> all_output.log
This line of command willcommandAll output (standard output and error) is written toall_output.log。
`2>&1` merges standard error into standard output to facilitate unified management. For example:
command > output.log 2>&1
This line of instruction will write to both standard output and erroroutput.log。
If you don't want any output to be displayed, you can direct all output to/dev/null,like:
command >/dev/null 2>&1
This line of command willcommandAll output is discarded.
in useteeWhen the command appends output to a file, you can passiconvConvert the output to UTF-8 encoding, ensuring the file contents are saved in UTF-8. Below are specific instructions and examples.
The following saves the output as UTF-8 encodedteeInstruction format:
command | iconv -t utf-8 | tee -a output.txt
-tRepresents "target encoding".output.txtdocument.The following example demonstrates how tolsThe output of the command is written in UTF-8 encoding tooutput.txt:
ls | iconv -t utf-8 | tee -a output.txt
After executing this instruction,output.txtThe content will be saved in UTF-8 encoding to avoid encoding errors.
Win + Rentercmdand press EntercmdCan be opened directly from this pathdir: Display files and folders in the current directorycd: Switch directories, for examplecd C:\Userscls:Clear screen contentcopy: Copy files, for examplecopy a.txt b.txtdel: Delete filesmkdir:Create a new folderrmdir: Delete folderecho: Output text, for exampleecho Helloexit: Close command prompt charactersdir > file.txtOutput results to filedir | find "txt"filter containstxtthe result.batFile executes multiple commands at oncesetView and set variablesipconfig /flushdnsorsfc /scannowWaiting for system maintenance instructionsCan be used&、&&or||To continue the instructions:
cmd /k "First command & Second command"
&: Regardless of whether the first one succeeds or fails, the next one will be executed.&&: Only execute the next one if the first one succeeds||: Only execute the next one if the first one failsAfter the first instruction addcall, you can continue to execute another batch file:
cmd /k "First command & call second.bat"
If you don't need to keep the window open, you can use/c:
cmd /c "First command & Second command"
/cwill automatically close the window after executing all commands, and/kThe window will be retained.
In the Windows Command Prompt (CMD), variables are namespaces used to store data or settings. They can be stored in the environment (environment variables) or defined and used in the batch file (regional variables).
Variables set by the system or user are available throughout the operating system session. For example:%PATH%、%TEMP%。
View environment variables:usesetOrder.
set
Set/modify environment variables (current CMD session only):
set MY_VAR=Hello
In the batch file (.bator.cmdfile)setThe variables defined by the command are only valid during the execution of this batch file.
in useforVariables defined when looping, used to iterate over files, folders, or numeric sequences. Usually named with a single letter preceded by two percent signs, for example:%%A(in a batch file) or a single percent sign, for example:%A(When executed directly from the command line).
Parameters passed to the batch file when executing it. For example:%1is the first parameter,%2is the second parameter,%0Is the path and name of the batch file itself.
To get the value of a variable, you usually need to add percent signs before and after the variable name.%。
set NAME=CMD User
echo My name is %NAME%
Output:My name is CMD User
@echo off
set MESSAGE=This is a batch message
echo%MESSAGE%
pause
You can useIF DEFINEDorIF NOT DEFINEDstatement to check whether the variable already exists or is defined (not empty).
@echo off
rem checks whether the variable MY_DEFAULT_VALUE is defined (not empty)
IF NOT DEFINED MY_DEFAULT_VALUE (
set MY_DEFAULT_VALUE=Default_Setting
The echo variable MY_DEFAULT_VALUE is undefined and has been set to the default value.
) ELSE (
echo variable MY_DEFAULT_VALUE already exists, the value is: %MY_DEFAULT_VALUE%
)
rem is executed once, the variable will be set to Default_Setting
If rem is executed again, it will show that it already exists.
set MY_DEFAULT_VALUE=Existing_Setting
rem check again
IF NOT DEFINED MY_DEFAULT_VALUE (
set MY_DEFAULT_VALUE=Another_Default
echo variable MY_DEFAULT_VALUE is undefined, set to Another_Default.
) ELSE (
echo variable MY_DEFAULT_VALUE already exists, the value is: %MY_DEFAULT_VALUE%
)
pause
Another neat trick is to take advantage of variable augmentation's default value functionality (but this is mainly used for loops and parameter processing, and in standardsetThe logic of "set if not set" is not directly applicable to the command. therefore,IF NOT DEFINEDThis is the most standard approach. )
In loops or conditional statements, standard percent sign variable expansion occurs once during statement parsing. In order to be able to read the new value of the variable on each iteration of the loop, you need to enable lazy expansion and use the exclamation mark!to reference variables.
@echo off
setlocal enabledelayeexpansion
setCOUNTER=0
:LOOP
if %COUNTER% LSS 5 (
set /A COUNTER+=1
echo current count: !COUNTER!
goto LOOP
)
endlocal
| variable | describe |
|---|---|
%DATE% |
current date. |
%TIME% |
current time. |
%CD% |
The current directory path. |
%ERRORLEVEL% |
The end code of the previous command (usually 0 for success). |
%RANDOM% |
A random decimal number between 0 and 32767. |
%~dp0 |
The drive and path where the batch file is being executed. |
For parameter variables (such as%1) or a loop variable (such as%%A), you can use modifiers to extract different parts of the path:
echo full path: %~1
echo drive: %~d1
echo path: %~p1
echo file name: %~n1
echo file extension: %~x1
This is useful when working with archive paths.
grep, but you can use the built-infindcommand achieves a similar effect.Command | find "keyword"dir | find "txt" :: Only show files containing "txt"
ipconfig | find "IPv4" :: Only show lines containing IPv4
tasklist | find "chrome" :: Filter out executable programs containing chrome
/I: Ignore case, for examplefind /I "error"/V: Display lines that do not contain keywords/C: Only display the number of matching rowsfindMeet the AND condition:type log.txt | find "Error" | find "2025"
findstr:type log.txt | findstr /I "error warning fail"
findstrIt is a CMD version of the advanced search tool that supports multiple keywords and regular expressions.dir | findstr /R ".*\.txt$" :: Use regular expressions to find .txt files
type log.txt | findstr /I "timeout error fail"
~/.bash_profileor~/.bashrc。AutoRunSettings will be executed automatically if there is any content.HKEY_CURRENT_USER\Software\Microsoft\Command Processor
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor
AutoRun, the content can be set to the batch file path to be executed:AutoRun = "C:\Users\YourName\cmd_startup.bat"
%SystemRoot%\System32\cmd.exe /k "C:\Users\YourName\cmd_startup.bat"
/kExecute the batch file after startup and keep the window open.%AppData%\Microsoft\Windows\Start Menu\Programs\Startup
| Linux bash | Windows CMD corresponding method |
|---|---|
| ~/.bash_profile or ~/.bashrc | Login form AutoRun or CMD /k starts the batch file |
| Automatically execute custom instructions | Customized environment variables and path settings can be placed in the batch file |
HKEY_CURRENT_USER\Software\Microsoft\Command Processorexists.AutoRunvalue, it will be automatically created and set as the specified batch file path.@echo off
setlocal
:: Set the batch file path to be executed by AutoRun
set "AUTORUN_PATH=C:\Users\%USERNAME%\cmd_startup.bat"
set "REG_PATH=HKCU\Software\Microsoft\Command Processor"
echo Check CMD AutoRun setting...
:: Check whether the login code exists
reg query "%REG_PATH%" >nul 2>&1
if errorlevel 1 (
echo [Information] The Command Processor code cannot be found, creating...
reg add "%REG_PATH%" /f >nul
)
:: Check if AutoRun is set
reg query "%REG_PATH%" /v AutoRun >nul 2>&1
if errorlevel 1 (
echo [Information] AutoRun not found, creating new value...
reg add "%REG_PATH%" /v AutoRun /d "%AUTORUN_PATH%" /f >nul
echo [Done] AutoRun has been set to: %AUTORUN_PATH%
) else (
echo [OK] AutoRun already exists and has not been changed.
)
endlocal
pause
reg query: Used to check whether the login key or value exists.errorlevel: Can be used to determine whether the query result is successful (0 means exists, 1 means does not exist).reg add: Create a login key or value./f: No prompt for forced coverage.%AUTORUN_PATH%Change it to the batch file path that you want to automatically execute when CMD starts.@echo off
:: Detect PowerShell
if defined PSModulePath (
echo is currently executed in PowerShell
goto :eof
)
:: Detecting Cygwin
if defined CYGWIN (
echo is currently executed in Cygwin
goto :eof
)
if defined SHELL (
echo is currently executed in Cygwin (SHELL=%SHELL%)
goto :eof
)
::Default is CMD
echo is currently executed in CMD
PSModulePathwill existCYGWINvariable, orSHELL=/bin/bashWin + XSelect "Windows PowerShell" or "Windows Terminal"powershellCan be opened directly from this pathGet-ChildItem: List files and folders in the current directory (similar todir)Set-Location: Switch directory (abbreviationcd)Clear-Host:Clear screen content (abbreviationcls)Copy-Item:Copy files or foldersRemove-Item: Delete files or foldersNew-Item:Create a new file or folderWrite-Output: Output text (abbreviationecho)Exit:Close PowerShellGet-Process | Where-Object {$_.CPU -gt 100}Get-ChildItem > file.txtls、cp、rmCan be used directly$var = "Hello", output$var.ps1File execution multiple commandsGet-EventLog、Set-ExecutionPolicyWaiting for system maintenance instructionsGet-Variable: Displays all variables in the current PowerShell sessionGet-ChildItem variable:: View all variables through variable driver# List all variables
Get-Variable
# Show only variable names
Get-Variable | Select-Object Name
# Display the value of a specific variable
Get-Variable PATH | Format-List *
#Use variable driver method
Get-ChildItem variable:
variable:Can be used as a path to manipulate variables, for exampleGet-Content variable:PATHWhere-Object,For example:Get-Variable | Where-Object { $_.Name -like "P*" }Only show variables starting with PPreprocessor Directives are commands executed by a program module called "Preprocessor" before the C or C++ program code is officially processed (compiled) by the compiler. These instructions are preceded by a pound sign (#) and not preceded by a semicolon (;) at the end.
The role of the preprocessor is to perform text replacement, file inclusion, conditional compilation and other operations to generate the final "Translation Unit" for use by the compiler.
Used to insert the contents of other files into the current file.
#include <filename>: Used to include standard library header files. The preprocessor searches for files in the compiler's default system header file path.#include "filename": Used to contain user-defined header files. The preprocessor will first search the directory of the current source code file, and then search the system path.#include <iostream> // Include the standard I/O library
#include "my_utility.h" // Include custom header file
Literal replacement macro used to define symbolic constants or code fragments.
#define: Define macro.#undef: Undefine macro.#define MAX_SIZE 100 //Define a symbolic constant
#define SUM(a, b) ((a) + (b)) // Define a macro with parameters
int main() {
int size = MAX_SIZE; // After preprocessing, it becomes int size = 100;
int total = SUM(5, 3); // After preprocessing, it becomes int total = ((5) + (3));
return 0;
}
Allows you to decide whether a specific block of code should be compiled based on the value of a preprocessor macro.
#ifdef: If the macro is defined, compile subsequent blocks.#ifndef: If the macro is not defined, compile subsequent blocks. (commonly used in Include Guard)#if: Determine whether to compile based on the value of the given constant integer expression.#else / #elif: Substitution or subsequent judgment of conditional compilation.#endif: End the conditional compilation block.#define DEBUG_MODE 1
#if DEBUG_MODE
std::cout << "Debug mode enabled" << std::endl;
#else
std::cout << "Production mode running" << std::endl;
#endif
#ifndef MY_HEADER_H
#defineMY_HEADER_H
// ... header file content (Include Guard example)
#endif
#error: Forces the preprocessor to stop compilation when encountering this directive and display the specified error message.#warning: Output the specified warning message without stopping compilation (non-standard directive, but supported by many compilers).#ifndef VERSION_DEFINED
#error "Must define version number macro VERSION_DEFINED!"
#endif
#pragma: Used to send special instructions to the compiler, the behavior is highly dependent on the compiler (e.g.#pragma onceand#pragma warning)。#line: Used to change the current line number and file name displayed when the compiler reports errors or warnings.#pragma onceIs one of the C and C++ languagesPreprocessor Directive. Its core function is to ensure that the header file containing this directive will only be processed by the compiler during a single compilation process.once。
The purpose of this directive is to solve the problem of repeated inclusion of header files and prevent the same piece of code (such as class definitions, function prototypes or constant declarations) from being seen multiple times by the compiler due to multiple source code files or multi-level header file inclusion relationships, thereby causingRedefinitioncompilation error.
In the C/C++ standard, traditionally by usingInclude GuardTo achieve the purpose of preventing repeated inclusion.#pragma onceProvides a cleaner alternative.
This is the standard and portable approach, using conditional compilation directives:
#ifndef MY_HEADER_H
#defineMY_HEADER_H
// Header file content
#endif // MY_HEADER_H
It relies on a unique macro name (e.g.MY_HEADER_H) to control whether content is included.
Use a single line directive:
#pragma once
// Header file content
The compiler will automatically track whether it has already processed this file in the current compilation session, and if so, skip the remaining contents of the file.
In modern development environments, especially when using Visual Studio or mainstream compilers,#pragma onceBecause of its simplicity and convenience, it prevents repeated inclusion of header files.Common and recommendedpractices.
#pragma warningare preprocessor directives in the C and C++ languages that are used within specific blocks of code.Selectively suppress, restore, or modify the severity of compiler warnings。
The main purpose of this directive is to provide finer control than project-level settings. Use this command, for example, when you need to include an older version of a library that generates a lot of warnings, but don't want to turn off the warnings globally.
Although#pragma warningThe specific implementation may vary slightly between different compilers (especially MSVC is the most widely used), but its core actions are divided into the following types:
From this point on, the compiler ignores the specified warning code.
#pragma warning( disable : 4996 ) // Disable C4996 (for example: warning about using unsafe functions)
// Contain or write code that will generate C4996
Restores the specified warning to the default behavior set by the project or command line.
#pragma warning(default: 4996) //Restore C4996 to default state
This is the safest and most recommended mode. It allows the warning settings to be modified while processing a specific block of code, and then ensures that the original warning state is restored immediately after the block ends to avoid side effects.
#pragma warning( push ): Store the current stacking status of warning settings.#pragma warning( pop ):Restore to the latestpushThe stored state.#pragma warning( push ) // 1. Save the current warning settings
#pragma warning( disable : 4996 4244 ) // 2. Disable multiple specific warnings
// Contains third-party header files or legacy code
#pragma warning( pop ) // 3. Restore to original settings
// Subsequent code will use the restored settings
Promote a specific warning code to a compilation error. If the warning occurs, compilation will fail.
#pragma warning( error : 4005 ) // Treat warning 4005 as an error
4996)yescompiler specific. You must look up the correct number for the compiler you are using (such as MSVC).#pragma warningfunctions, but they generally prefer to use-W...command line flags or special#pragma GCC diagnosticStructure to control warnings.In C++ programming,std::Refers to the Standard Namespace. It is a container that contains all standard entities in the C++ language core and its Standard Library (Standard Library), including functions, classes, templates, macros, and objects.
usestd::The main purpose is to avoidName Collisions. If a standard function (e.g.coutorvector) are not placed in a separate namespace. When the user defines an entity with the same name, the compiler will not know which one to use.
Most of the functionality of the C++ standard library is located instd::within the namespace. Main categories and features include:
std::cout: Standard output streaming object, used to print data to the console.std::cin: Standard input stream object, used to read data from the console.std::endl: Output newlines and flush the buffer.std::ifstream / std::ofstream: File input/output streaming.Collection categories used to store data:
std::vector:A dynamically sized array.std::list: Two-way connection sequence.std::map: A sorted collection of key-value pairs (red-black tree implementation).std::unordered_map: An unordered collection of key-value pairs (hash table implementation).std::set: A sorted collection of unique key values.std::string: Category used for processing strings.A set of common functions for container and range operations:
std::sort: Sort elements within the range.std::find: Find the specified value within the range.std::copy: Copies elements from one range to another.std::shared_ptr / std::unique_ptr: Intelligent indicators for automated memory management.std::thread: Used for multi-thread programming.std::function: Universal function wrapper.std::pair / std::tuple: Template used to store a fixed number of values of different types.to accessstd::There are two main methods for entities in a namespace:
Write it clearly every time you use itstd::prefix. This is the safest and recommended approach, especially in header files, to avoid polluting the global namespace.
int main() {
std::cout << "Hello World" << std::endl;
std::vector<int> numbers;
return 0;
}
useusing namespace std;The entirestd::The contents of the namespace are introduced into the current scope, and the name can be used directly withoutstd::prefix.
#include <iostream>
using namespace std; // Introduce std:: namespace
int main() {
cout << "Hello World" << endl; // No std:: prefix required
vector<int> numbers;
return 0;
}
althoughusing namespace std;Convenient, but should be avoided in large projects or header files as it increases the risk of naming conflicts.
In C++,std::stringIs a category (Class). When you declare astd::stringWhen a variable is not given an initial value, it calls the Default Constructor.
"")。0。NULLindicator, but a valid object.#include <string>
#include <iostream>
void initialization_example() {
std::string s; // declared but no value given
std::cout << "Length: " << s.length() << std::endl; // Output: 0
std::cout << "Content: '" << s << "'" << std::endl; // Output: ''
}
To check if a string does not contain any characters, the most recommended way is to useempty()member functions, which are better than checkinglength() == 0More semantic and more efficient in some containers.
void check_empty(std::string s) {
if (s.empty()) {
std::cout << "This is an empty string." << std::endl;
}
}
This is a common misunderstanding:The std::string object itself is never null.
In C++, only "pointers" can benullptr. If you are referring to checking whether a string has not been assigned a value, usually checking whether itempty(). If you are dealing with C-style string pointers (char*), you need to check for null.
| type | Check method | Remark |
|---|---|---|
| std::string s; | s.empty() | Check if content length is 0 |
| std::string* ptr; | ptr == nullptr | Check if the "indicator" itself points to a gap |
| char* c_str; | c_str == nullptr | Check if C-style string pointer is empty |
If you want to restore an existing string to its original empty state, you can use the following method:
void clear_example() {
std::string s = "Hello";
s.clear(); // Method 1: Most commonly used
s = ""; // Method 2: Reassign
s = std::string(); // Method 3: Assign a default object
}
This is the most straightforward method introduced in C++11, converting a numeric value into a string. By default, it retains 6 decimal places.
#include <string>
#include <iostream>
void simple_convert() {
float val = 3.14159f;
std::string s = std::to_string(val);
std::cout << s << std::endl; // Output example: "3.141590"
}
If you need to control the number of decimal places or a specific format,stringstreamIt is the most flexible option. it combines<iomanip>library to precisely control the output.
#include <sstream>
#include <iomanip>
void precision_convert() {
float val = 3.1415926f;
std::stringstream ss;
// Set fixed point counting method (fixed) and retain 2 decimal places
ss << std::fixed << std::setprecision(2) << val;
std::string s = ss.str();
std::cout << s << std::endl; // Output: "3.14"
}
In C++20, you can use format strings to handle type conversion and precision control at the same time, with the most concise syntax.
#include <format>
void modern_format() {
float val = 123.456f;
// {:.2f} represents float type and retains two decimal places
std::string s = std::format("{:.2f}", val);
std::cout << s << std::endl; // Output: "123.46" (will be automatically rounded)
}
std::to_stringOften there are extra zeros like "3.140000". you can combinefind_last_not_ofanderaseto clean up the string.
std::string remove_trailing_zeros(float val) {
std::string s = std::to_string(val);
// Remove trailing '0' until non-zero character is encountered
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
// If the last character is a decimal point, also remove it
if (s.back() == '.') {
s.pop_back();
}
return s;
}
| method | Features | Suggested scenarios |
|---|---|---|
| std::to_string | The syntax is the shortest and the performance is acceptable | Quick debugging, when there are no requirements on the number of decimal places |
| std::stringstream | Highly customizable (zero padding, width, carry) | When the output format needs to be strictly controlled |
| std::format | Type safety, performance, and modern syntax | Preferred solution in C++20 environment |
| sprintf (C style) | Extremely fast but less safe | Maintenance of old code with extreme pursuit of performance |
This is the most standard approach in C++ that does not rely on external libraries. throughfindFind the position of the delimiter and usesubstrRetrieve substring.
#include <iostream>
#include <vector>
#include <string>
void split_by_three_chars() {
std::string text = "Apple---Banana---Cherry---Date";
std::string delimiter = "---";
std::vector<std::string> tokens;
size_t pos = 0;
size_t last_pos = 0;
//Loop to find delimiter
while ((pos = text.find(delimiter, last_pos)) != std::string::npos) {
tokens.push_back(text.substr(last_pos, pos - last_pos));
last_pos = pos + delimiter.length();
}
//Put in the last fragment
tokens.push_back(text.substr(last_pos));
//output result
for (const auto& t : tokens) std::cout << "[" << t << "]" << std::endl;
}
If your string is very large, usestd::string_viewIt can avoid generating a large number of string copies during the splitting process, thereby greatly improving performance.
#include <string_view>
#include <vector>
std::vector<std::string_view> split_sv(std::string_view str, std::string_view del) {
std::vector<std::string_view> output;
size_t first = 0;
while (first < str.size()) {
const auto second = str.find(del, first);
if (second == std::string_view::npos) {
output.emplace_back(str.substr(first));
break;
}
output.emplace_back(str.substr(first, second - first));
first = second + del.size();
}
return output;
}
If you want your code to look more concise, or if the separators may change, you can usestd::regex. But note that the execution performance of regular expressions is usually better than that of manualfindslow.
#include <regex>
void regex_split() {
std::string text = "One###Two###Three";
std::regex ws_re("###"); // Define 3 character separator
std::copy(std::sregex_token_iterator(text.begin(), text.end(), ws_re, -1),
std::sregex_token_iterator(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
| method | advantage | shortcoming |
|---|---|---|
| std::find + substr | Highest compatibility (C++98+) and stable performance. | The code is lengthy and requires manual processing of the last fragment. |
| string_view | Most effective, no additional memory copy is generated. | Requires C++17 support, and attention must be paid to the original string life cycle. |
| std::regex | The syntax is the most concise and extensible. | The execution speed is the slowest and the compilation time is longer. |
In C++, to checkstd::vectorIf the container contains no elements (i.e. has size zero), the most standard and recommended way is to use its member functionsempty(). This is becauseempty()Functions are usually better than direct checkssize()Is equal to zero more efficient, especially in some container implementations.
This is the preferred way to check if a vector is empty. It returns a Boolean value: if vector has no elements, it returnstrue; Otherwise returnfalse。
#include <vector>
#include <iostream>
#include <string>
void check_empty(const std::vector<std::string>& vec)
{
if (vec.empty()) {
std::cout << "Vector is empty (empty() == true)." << std::endl;
} else {
std::cout << "Vector is not empty (empty() == false). Number of elements: " << vec.size() << std::endl;
}
}
int main()
{
std::vector<std::string> empty_vec;
std::vector<std::string> non_empty_vec = {"apple", "banana"};
check_empty(empty_vec);
check_empty(non_empty_vec);
return 0;
}
While valid, this is not the most idiomatic or potentially most efficient way of checking for empty state. It directly checks whether the number of elements in the vector is zero.
void check_size(const std::vector<int>& vec)
{
if (vec.size() == 0) {
std::cout << "Vector is empty (size() == 0)." << std::endl;
} else {
std::cout << "Vector is not empty (size() != 0)." << std::endl;
}
}
forstd::vectorIn terms ofempty()andsize() == 0The time complexity is $O(1)$ because vector stores its size as a member variable. However, for some other C++ standard containers (e.g.std::listorstd::forward_list), the standard recommendation is always to useempty(), because it is generally the most common and fastest idiom in the C++ standard container library for checking for empty status.
In C++, a character containing a space (Space) or Tab character (\t) separated string is parsed into individual words or tokens and stored instd::vector<std::string>, the most common method is to use **std::stringstream**. File streaming categorystd::stringstreamLike an in-memory stream, it defaults to using whitespace characters (including spaces, tabs, and newlines) as delimiters for reading operations.
The following is usedstd::stringstreamExample of C++ code that accomplishes this task:
#include <iostream>
#include <sstream> // include stringstream
#include <string>
#include <vector>
using namespace std;
/**
* Separate the input string by any whitespace characters (space or Tab) and store it in the vector.
* @param input_str The string to be parsed.
* @return A vector containing all separated words.
*/
vector<string> split_string_by_whitespace(const string& input_str)
{
vector<string> tokens;
// 1. Create a stringstream object and initialize it with the input string
stringstream ss(input_str);
string token;
// 2. Loop reading
// The stream extraction operator (>>) will automatically read the next token using whitespace characters (space, Tab, etc.) as delimiters.
// The operator returns true when a token is successfully read, otherwise (the end of the string is reached) it returns false.
while (ss >> token)
{
tokens.push_back(token);
}
return tokens;
}
int main()
{
//The input string contains multiple spaces and tab symbols (\t)
string test_string = "Hello \tWorld this is \ta test string";
cout << "Original string: " << test_string << endl;
vector<string> result = split_string_by_whitespace(test_string);
cout << "--- separate results ---" << endl;
for (size_t i = 0; i < result.size(); ++i)
{
cout << "Token " << i + 1 << ": [" << result[i] << "]" << endl;
}
return 0;
}
std::stringstream ss(input_str): This category treats the input string as an input stream (Input Stream), and its function is similar to that used when reading from a file.std::ifstream。>>):
while (ss >> token): This is an idiomatic C++ stream read loop. As long as the stream successfully extracts and stores the data totokenvariable, the loop will continue to execute.In C++/CLI,gcnew System::String(stdStr.c_str())willstd::string(usuallyANSI / UTF-8encoding) directly into .NETSystem::String,andSystem::StringThe expectation isUTF-16。
ifstdStrIf it contains non-ASCII characters (such as Chinese), garbled characters will appear.
marshal_as(suggestion)Namespace needs to be quoted:
#include <msclr/marshal_cppstd.h>
using namespace msclr::interop;
std::string stdStr = "Chinese test";
System::String^ netStr = marshal_as<System::String^>(stdStr);
✅ This method can automatically convert UTF-8 / ANSI to .NET Unicode correctly.
---#include <codecvt>
#include <locale>
std::string utf8Str = u8"Chinese test";
std::wstring wideStr = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>{}.from_bytes(utf8Str);
System::String^ netStr = gcnew System::String(wideStr.c_str());
---
std::wstringIf the C++ side originally uses wide character strings, just use it directly:
std::wstring wstr = L"Chinese test";
System::String^ netStr = gcnew System::String(wstr.c_str());
---
std::stringThe source is UTF-8 (common in modern systems) → usemarshal_asorcodecvt。gcnew String(stdStr.c_str()), unless the string is pure English.In C++, you can usestd::arrayInitialize a multidimensional array to 0:
#include <iostream>
#include <array>
using namespace std;
int main() {
array<array<int, 4>, 3> arr = {0}; // Initialize all elements to 0
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
cout << arr[i][j] << " ";
}
cout << endl;
}
return 0;
}
std::arrayIs a container class in the C++ standard library, suitable for situations where the size is fixed at compile time.std::arrayProvides more functionality and security.In C++, looping is the basic operation of iterating over all elements in a container or array.std::vector(dynamically sized container) andstd::array(fixed-size containers) are containers in the C++ Standard Library (STL) whose elements can be iterated over in a variety of standard and safe ways.
This is the most modern, safest, and most concise traversal method introduced in C++11. It works with all standard containers (includingstd::vectorandstd::array)。
std::vector: **Preferred**std::array: **Preferred**#include <iostream>
#include <vector>
#include <array>
void range_based_loop_example()
{
std::vector<int> vec = {10, 20, 30};
std::array<int, 4> arr = {1, 2, 3, 4};
// Use auto& to traverse by reference, which is efficient and allows modification of elements
std::cout << "--- Vector (modifiable) ---" << std::endl;
for (auto& element : vec) {
element += 1; // Modify element
std::cout << element << " ";
}
std::cout << std::endl;
// Use const auto& to traverse by constant reference, which is safe and does not allow modification of elements
std::cout << "--- Array (read only) ---" << std::endl;
for (const auto& element : arr) {
std::cout << element << " ";
}
std::cout << std::endl;
}
This is a traditional and universal method. Suitable for situations where you need to access element indexes (for example: you need to operate two containers or arrays at the same time, or terminate at a specific index).
std::vector:applicable, usesize()Get the boundaries.std::array:applicable, usesize()Get the boundaries.#include <iostream>
#include <vector>
#include <array>
void index_loop_example()
{
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
std::array<double, 3> prices = {10.5, 20.99, 5.0};
// Use size_t or auto with size() to ensure the index type is correct and the bounds are safe
for (size_t i = 0; i < names.size(); ++i) {
// Use operator[] to access elements
std::cout << "Name: " << names[i] << ", Price: " << prices[i] << std::endl;
}
}
NOTE: Use[]C++ does not perform bounds checking when operators access elements. If bounds checking is required, useat()function (it will throw when out of boundsstd::out_of_rangeabnormal).
This is the most flexible traversal method in C++ and works with all standard containers. Iterators are necessary when interacting with C++ Standard Library (STL) algorithms.
std::vector: **Recommended** (when STL algorithm or specific control is required)std::array: **Recommended** (when STL algorithm is required)#include <iostream>
#include <vector>
void iterator_loop_example()
{
std::vector<double> values = {100.0, 50.0, 10.0};
// Simplify the iterator type using auto and use begin() and end() to get the range
for (auto it = values.begin();
it != values.end();
++it)
{
*it /= 10.0; // *it dereferences the iterator and accesses elements
std::cout << *it << " ";
}
std::cout << std::endl;
// Use cbegin() and cend() to ensure the iterator is const for read-only traversal
for (auto cit = values.cbegin(); cit != values.cend(); ++cit)
{
// Trying *cit = 5; will result in a compilation error
std::cout << *cit << " ";
}
std::cout << std::endl;
}
| loop method | Applicable containers | advantage | Applicable time |
|---|---|---|---|
| Range-based | std::vector, std::array, all standard containers | The cleanest, safest, modern C++ idiom. | No index is needed, only each element needs to be traversed. |
| Index-based | std::vector, std::array | Indexes can be accessed and have high versatility. | When you need to know or manipulate the index of an element. |
| Iterator | All standard containers | Extremely flexible and can be used with STL algorithms such asstd::find) fits perfectly. |
When you need to use STL algorithms or perform complex operations on containers. |
std::array<std::array<std::array<float, 2>, 2>, 2> twoLines;
std::array<std::array<std::array<float, 2>, 2>, 2> twoLinesCopy;
std::arraySupports complete copying from shallow to deep levels, so it can be used directly=:
twoLinesCopy = twoLines;
std::copy(twoLines.begin(), twoLines.end(), twoLinesCopy.begin());
std::memcpy(&twoLinesCopy, &twoLines, sizeof(twoLines));
twoLinesCopy = twoLines;std::copySuitable for applications requiring STL generic methods.memcpyOnly applicable to POD (Plain Old Data), and no constructor/deconstructor logic.In C++, this happens when you access an invalid or out-of-bounds memory location when you manipulate pointers or use indexes to access arrays/memory.Undefined Behavior. This behavior usually manifests itself as a programCrash, such as a Segmentation Fault or Access Violation error.
C++ standardtry-catchThe mechanism is mainly used to catch C++ exceptions (Exceptions) that are explicitly thrown in the program code, but cannot directly catch hardware or memory access errors issued by the operating system.
When a C++ program attempts to access invalid memory, for example:
nullptrof memory.deleteorfreeFreed memory.These operations will trigger the protection mechanism of the underlying operating system (such as Access Violation on Windows or SIGSEGV signal on Unix/Linux), and the program will be terminated by the operating system. These errors are not C++ language-level exception objects (such asstd::exception), so the standardtry-catchThere is no way to capture them.
#include <iostream>
#include <vector>
using namespace std;
void crash_function()
{
// Array out-of-bounds access example
vector<int> vec = {10, 20};
cout << "Attempt to access out-of-bounds index..." << endl;
// This is undefined behavior and is likely to lead to an access violation crash
int value = vec[100]; // Error: Accessing invalid index
cout << "value: " << value << endl;
}
int main()
{
try
{
crash_function();
//The program will crash at vec[100] above and will not be executed here.
// And the catch block will not be executed.
}
catch (const exception& e)
{
// Operating system level errors cannot be captured here
cerr << "Caught C++ exception: " << e.what() << endl;
}
catch(...)
{
// Still unable to catch memory access errors
cerr << "Unknown exception caught" << endl;
}
return 0;
}
The best approach is to prevent such errors from happening during the design phase of your code rather than trying to catch them:
std::vectorandstd::string,useat()member function instead[]operator. whenat()When out of bounds, it throws a C++ exceptionstd::out_of_range, can be standardizedtry-catchcapture.std::unique_ptr, std::shared_ptr) to automate the memory life cycle. Never dereferencenullptr, and checks whether the pointer is valid before dereferencing it.void safe_function()
{
vector<int> vec = {10, 20};
try
{
int value = vec.at(100); // throw std::out_of_range exception
cout << "value: " << value << endl;
}
catch (const std::out_of_range& e)
{
// Successfully caught C++ exception
cerr << "Safe capture: " << e.what() << endl;
}
}
In a Windows environment, you can use Microsoft's extended Structured Exception Handling (SEH) to catch operating system-level errors, including Access Violations. This is usually done using__tryand__exceptKeywords.
Note: SEH is non-standard and not recommended for use in portable C++ code. In C++/CLI projects, you can use .NET'stry/catchCatch some SEH exceptions, but this requires specific compiler settings (e.g./EHa)。
In C++, when you use a raw array (C-style array) or pointer for indexing operations, it occurs if a memory location that is outside the range of the array or is invalid is accessed.Undefined Behavior. This behavior often results in programs running at the operating system levelCrash, such as Access Violation or Segmentation Fault.
The key points are:C++ standardtry-catchThe mechanism is designed to catch C++ exceptions (Exceptions) that are explicitly thrown in the program code. It cannot catch hardware or memory protection errors issued by the operating system.
When a C++ program attempts to access invalid memory (for example, accessing a static arrayarr[100], but the array only has 10 elements), which violates the operating system's memory protection rules. The operating system steps in and sends a signal or exception to terminate the program, preventing it from damaging the system or other programs. These errors are not C++ language levelstd::exceptionobject and therefore cannot be used by the standardtry-catchBlock capture.
#include <iostream>
#include <stdexcept> // Include standard exceptions
using namespace std;
void crash_function()
{
// C-style primitive array
int raw_array[5] = {1, 2, 3, 4, 5};
cout << "Attempt to access out-of-bounds index..." << endl;
// Array out-of-bounds access: This is a typical undefined behavior
// If a memory that the program does not have permission to access is accessed, an access violation will be triggered immediately, causing the program to crash.
int value = raw_array[100]; // Error: Accessing invalid index
cout << "Value (if reachable): " << value << endl;
}
int main()
{
try
{
crash_function();
// The program will terminate at raw_array[100] and will not be executed here.
}
catch (const exception& e)
{
// Operating system level memory access errors cannot be captured here
cerr << "Caught C++ exception: " << e.what() << endl;
}
return 0;
}
The best practice is to avoid out-of-bounds accesses entirely, or to use the safe containers and methods provided by C++, which throw catchable C++ exceptions when an error occurs:
forstd::vectorcontainer, useat()member function instead of original[]operator. When access goes out of bounds,at()will throw **std::out_of_range**Exception, this is a standard C++ exception and can betry-catchCaught and disposed of safely.
#include <vector>
// ... (other include)
void safe_vector_access()
{
std::vector<int> vec = {10, 20};
try
{
// Use at() for bounds checking
int value = vec.at(100);
std::cout << "value: " << value << std::endl;
}
catch (const std::out_of_range& e)
{
// Successfully caught C++ exception
std::cerr << "Safely caught out-of-bounds exception: " << e.what() << std::endl;
}
}
Introduced using C++11std::arrayReplaces C-style arrays. Althoughstd::arrayof[]The operator is not checked, but itsat()The function will also throwstd::out_of_rangeabnormal.
#include <array>
// ...
void safe_array_access()
{
std::array<int, 5> arr = {1, 2, 3, 4, 5};
try
{
int value = arr.at(5); // Access out of bounds, throw exception
}
catch (const std::out_of_range& e)
{
std::cerr << "std::array out-of-bounds capture: " << e.what() << std::endl;
}
}
On certain platforms such as Windows, you can use **Structured Exception Handling (SEH)** to catch hardware exceptions (such as access violations) issued by the operating system. This usually involves using a Microsoft extension__tryand__exceptKeywords. This method is platform non-standard, sacrifices code portability, and is generally not recommended as a routine error handling mechanism.
In .NET (languages like C++/CLI, C#, VB.NET, etc.),List<T>is a generic collection category,
Can store any type of data (T) and provide dynamic resizing function.
it belongs toSystem::Collections::Genericnamespace.
//Import namespace
using namespace System;
using namespace System::Collections::Generic;
int main()
{
// Declare a List to store int
List<int>^ numbers = gcnew List<int>();
//Add elements directly during initialization
List<String^>^ names = gcnew List<String^>({ "Alice", "Bob", "Charlie" });
}
List<int>^ nums = gcnew List<int>();
//Add new element
nums->Add(10);
nums->Add(20);
nums->Add(30);
//Insert at specified position
nums->Insert(1, 15); // Insert 15 at index 1
//Remove specified value
nums->Remove(20);
//Remove the specified index
nums->RemoveAt(0);
// Get elements
int value = nums[1]; // Get the element at index 1
// Check if it contains
if (nums->Contains(30))
Console::WriteLine("Found 30");
// Clear all elements
nums->Clear();
// for loop
for (int i = 0; i < nums->Count; i++)
{
Console::WriteLine("{0}th element: {1}", i, nums[i]);
}
// for each loop
for each (int n in nums)
{
Console::WriteLine(n);
}
| Properties/Methods | illustrate |
|---|---|
Count | Current number of elements |
Capacity | Internal capacity (can grow automatically) |
Add(item) | add an element |
AddRange(collection) | Join all elements of another collection |
Insert(index, item) | Insert element at specified position |
Remove(item) | Removes the specified value (first match found) |
RemoveAt(index) | Remove element at specified index |
Clear() | Remove all elements |
Contains(item) | Check if the specified value is contained |
IndexOf(item) | Returns the index of the element (-1 if it does not exist) |
Sort() | Sorting elements (for comparable types) |
Reverse() | Reverse the order of elements |
10 15 30
in C++/CLISystem::Collections::Generic::List<T>, if you try to access an index that doesn't exist (e.g.sizeis 1 but accessindex1), programWon'tGiven a default value (such as 0 or null), an exception will be thrown immediately.
System::ArgumentOutOfRangeExceptionBefore making an index access, you should always checkCountattribute, or usetry-catchBlocks capture potential errors.
//Method A: Pre-inspection (most recommended, best performance)
if (nums->Count > 1) {
int value = nums[1];
// Processing logic
} else {
// Handle insufficient index situation
}
//Method B: Exception catching
try {
int value = nums[1];
} catch (System::ArgumentOutOfRangeException^ ex) {
System::Diagnostics::Debug::WriteLine("Index out of range!");
}
| context | result | Remark |
|---|---|---|
| Index exists (e.g., Count=5, index=1) | Return the correct value | normal operation. |
| Index does not exist (e.g., Count=1, index=1) | throws ArgumentOutOfRangeException | The program will interrupt execution. |
| Native C++ array/std::vector [ ] | Undefined Behavior | You may get garbled code or crash, but will not actively throw .NET exceptions. |
nums[i]Confirm beforei < nums->Count。int value = (nums->Count > 1) ? nums[1] : 0;
System::Linq), you can useElementAtOrDefault(1), which returns the type's default value (0 for int) if the index does not exist.In C++, the most commonly used tools are defined in<algorithm>instd::minandstd::max. They support basic types, objects, and even initialization lists.
#include <algorithm>
#include <iostream>
#include <vector>
void basic_usage() {
int a = 10, b = 20;
// 1. Compare two numbers
int small = std::min(a, b);
int large = std::max(a, b);
// 2. Compare initialization lists (C++11)
int lowest = std::min({5, 1, 9, 3}); // return 1
// 3. std::minmax (C++11) - get the maximum and minimum values at the same time
auto result = std::minmax({10, 20, 30, 40});
std::cout << "Min: " << result.first << ", Max: " << result.second;
}
When you need to initialize a "minimum" variable, you usually set it to the largest positive number that the type can express, to ensure that it will be updated on the first comparison.
floatThe maximum value (about $3.4 \times 10^{38}$).doublethe maximum value.intthe maximum value.std::numeric_limitsProvides a consistent and templated way to obtain numeric properties, which is very useful when writing generic code.
#include <limits>
void limits_example() {
// Get the maximum value
float max_f = std::numeric_limits<float>::max();
int max_i = std::numeric_limits<int>::max();
// Get the "minimum positive number" (note: for floating point numbers, min() returns the minimum positive number instead of the maximum negative number)
float min_positive_f = std::numeric_limits<float>::min();
// Get the "lowest value" (the real smallest negative number)
float lowest_f = std::numeric_limits<float>::lowest();
}
If you are dealing withstd::vectoror array, you need to usestd::min_elementorstd::max_element, what they return isIterator。
#include <vector>
#include <algorithm>
void collection_example() {
std::vector<float> scores = {88.5f, 92.0f, 79.5f, 100.0f};
// Get the iterator of the maximum value
auto it = std::max_element(scores.begin(), scores.end());
if (it != scores.end()) {
std::cout << "Highest score: " << *it;
}
}
| name | use | Things to note |
|---|---|---|
| FLT_MAX | Initialize minimum value search | defined in<cfloat>, is a legacy macro from C. |
| std::min | Compare two numbers or lists | If the parameter types are inconsistent (such as int and long), the template needs to be specified explicitly:std::min<long>(a, b)。 |
| lowest() | Get the smallest negative number | In floating point numbers,min()is the smallest positive number close to 0,lowest()is the maximum negative value. |
| min_element | search container | What is returned is an iterator, and you need to check whether the container is empty before using it. |
In the C++ standard math library, although the constant definition of $\pi$ was not officially standardized until C++20, there are several commonly used methods to obtain approximate values of pi in different C++ versions and compiler environments.
To ensure code portability and accuracy, the most recommended approach is to use thestd::numbers::pi。
Starting with C++20, the standard library is<numbers>Precise and type-safe mathematical constants are provided in the header file.
#include <numbers>#include <iostream>
#include <numbers> // introduced in C++20
void use_cpp20_pi()
{
// std::numbers::pi_v<T> is a template variable that provides an exact value based on type T
// std::numbers::pi (without <T>) is equivalent to std::numbers::pi_v<double>
double pi_double = std::numbers::pi;
float pi_float = std::numbers::pi_v<float>;
long double pi_long_double = std::numbers::pi_v<long double>;
std::cout.precision(16); // Set output precision
std::cout << "C++20 (double): " << pi_double << std::endl;
std::cout << "C++20 (float): " << pi_float << std::endl;
}
Before C++20, many developers relied on the C math library (<cmath>or<math.h>) provides a non-standard macro. Although these macros exist on most modern systems, they are not part of the C++ standard and are not guaranteed to work in all environments.
#include <cmath>(or<math.h>)#include <iostream>
#include <cmath> // Traditional C math library
void use_c_macro_pi()
{
// M_PI is the most common PI macro, usually defined as double type.
// Note: To enable this macro, the _USE_MATH_DEFINES macro may need to be defined on some systems.
#ifdef M_PI
double pi_value = M_PI;
std::cout.precision(16);
std::cout << "C Macro (M_PI): " << pi_value << std::endl;
#else
std::cout << "The M_PI macro is undefined. You may need to define _USE_MATH_DEFINES." << std::endl;
#endif
}
If you cannot use C++20 or C macros, you can define $\pi$ yourself as a constant, or use a mathematical function to calculate it (e.g. $\arccos(-1)$).
#include <iostream>
#include <cmath>
void define_or_calculate_pi()
{
// Define through mathematical operations:
const double PI_CUSTOM_CALC = std::acos(-1.0);
// Define it directly as a constant:
const double PI_CUSTOM_DEFINE = 3.14159265358979323846;
std::cout.precision(16);
std::cout << "Custom Calculate: " << PI_CUSTOM_CALC << std::endl;
std::cout << "Custom Define: " << PI_CUSTOM_DEFINE << std::endl;
}
std::numbers::pi。const double PI = 3.14159...;M_PIMacro, but be aware of its non-standard nature.#include <cmath>
#include <iostream>
using namespace System;
using namespace System::Collections::Generic;
int main()
{
//Create test data
Dictionary<int, List<float>^>^ data = gcnew Dictionary<int, List<float>^>();
data->Add(1, gcnew List<float>({ 1.2f, 2.3f, 3.4f }));
data->Add(2, gcnew List<float>({ 4.5f, 5.5f, 6.5f, 7.5f }));
data->Add(3, gcnew List<float>()); // Test the empty list
// Calculate the standard deviation of each key
for each (KeyValuePair<int, List<float>^> entry in data)
{
int key = entry.Key;
List<float>^ values = entry.Value;
if (values == nullptr || values->Count == 0)
{
Console::WriteLine("Key {0}: No data", key);
continue;
}
// Calculate the average
double sum = 0.0;
for each (float v in values)
{
sum += v;
}
double mean = sum / values->Count;
// Calculate the number of mutations (number of maternal mutations)
double variance = 0.0;
for each (float v in values)
{
double diff = v - mean;
variance += diff * diff;
}
variance /= values->Count; // If you want the sample variation, change to (values->Count - 1)
// standard deviation
double stddev = Math::Sqrt(variance);
Console::WriteLine("Key {0}: standard deviation = {1:F4}", key, stddev);
}
return 0;
}
values->Count - 1。Key 1: Standard deviation = 0.8981 Key 2: Standard deviation = 1.1180 Key 3: No information
In .NET (languages like C++/CLI, C#, VB.NET, etc.),Dictionary<TKey, TValue>is a generic collection,
Used to store "key-value pairs". Each key must be unique, and the value must be repeatable.
it belongs toSystem::Collections::Genericnamespace.
//Import namespace
using namespace System;
using namespace System::Collections::Generic;
int main()
{
//Create a Dictionary with Key as int and Value as String
Dictionary<int, String^>^ users = gcnew Dictionary<int, String^>();
// Direct initialization
users->Add(1, "Alice");
users->Add(2, "Bob");
users->Add(3, "Charlie");
return 0;
}
Dictionary<String^, int>^ ages = gcnew Dictionary<String^, int>();
//Add new element
ages->Add("Tom", 25);
ages->Add("Jerry", 30);
//Modify value (via indexer)
ages["Tom"] = 26;
// Add or modify (if key does not exist, it will be added automatically)
ages["Spike"] = 40;
// delete element
ages->Remove("Jerry");
//Access elements
if (ages->ContainsKey("Tom"))
{
Console::WriteLine("Tom's age is {0}", ages["Tom"]);
}
// Try to get the value (avoid exceptions)
int age;
if (ages->TryGetValue("Spike", age))
{
Console::WriteLine("Spike's age is {0}", age);
}
Dictionary<int, String^>^ users = gcnew Dictionary<int, String^>();
users->Add(1, "Alice");
users->Add(2, "Bob");
users->Add(3, "Charlie");
// Use KeyValuePair loop
for each (KeyValuePair<int, String^> entry in users)
{
Console::WriteLine("Key = {0}, Value = {1}", entry.Key, entry.Value);
}
//Get only Keys
for each (int key in users->Keys)
{
Console::WriteLine("Key: {0}", key);
}
//Get only Values
for each (String^ name in users->Values)
{
Console::WriteLine("Name: {0}", name);
}
| Properties/Methods | illustrate |
|---|---|
Add(key, value) | Add a new set of key-value pairs |
Remove(key) | Removes the specified key and its corresponding value |
Clear() | Clear all projects |
ContainsKey(key) | Check if the specified key exists |
ContainsValue(value) | Check if the specified value exists |
TryGetValue(key, out value) | Get the value safely without throwing an exception |
Count | The current number of elements in the dictionary |
Keys | Returns a collection of all keys |
Values | Returns a collection of all values |
Key = 1, Value = Alice Key = 2, Value = Bob Key = 3, Value = Charlie Tom's age is 26 Spike's age is 40
std::sortIs the most commonly used sorting algorithm in the C++ Standard Template Library (STL). it is located<algorithm>In the header file, by default, elements within the range will beAscendingto sort.
#include <algorithm>
#include <vector>
#include <iostream>
void basic_sort() {
std::vector<int> nums = {5, 2, 9, 1, 5, 6};
// Sorting range: from start iterator to end iterator
std::sort(nums.begin(), nums.end());
// Result: 1, 2, 5, 5, 6, 9
}
You can change the sorting logic by passing in the third parameter (comparison function or lambda expression).
// 1. Use predefined std::greater for exponentiation
std::sort(nums.begin(), nums.end(), std::greater<int>());
// 2. Use Lambda expressions to customize logic
std::sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // When true is returned, a will be ranked in front of b
});
For custom types, comparison logic must be provided, otherwise the compiler will report an error because it does not know how to compare sizes.
struct Student {
std::string name;
int score;
};
void sort_students() {
std::vector<Student> students = {{"Alice", 90}, {"Bob", 85}, {"Charlie", 95}};
// Sort by score from high to low
std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {
return a.score > b.score;
});
}
std::sortNot a single sorting algorithm, but a hybrid algorithm designed to combine the advantages of each algorithm and avoid the worst-case scenario. Its operating logic is as follows:
| characteristic | illustrate |
|---|---|
| average time complexity | $O(n \log n)$ |
| Worst time complexity | $O(n \log n)$ (Benefit from the Introsort mechanism) |
| space complexity | $O(\log n)$ (recursive call stacking) |
| Stability | unstable(The relative positions of equal elements may change). If you need stable sorting, please usestd::stable_sort。 |
In C++, template is a generic programming tool that allows us to write functions or categories without specifying specific data types, thereby making the code more reusable. Templates help handle different types of data in a single code, avoiding duplicate function or class definitions.
Function templates allow us to write functions that can handle different types. The syntax of function template is as follows:
template <typename T>
T add(T a, T b) {
return a + b;
}
In this example,addThe function can handle any type that supports addition operations, such asint、floatordouble。
When using it, you can call it like this:
int result = add(3, 4); // use int type
double result2 = add(3.5, 2.7); // use double type
Category templates allow us to create categories that can be applied to multiple types. The syntax of a category template is as follows:
template <typename T>
class MyClass {
private:
T data;
public:
MyClass(T data) : data(data) {}
T getData() { return data; }
};
In this exampleMyClassCategories can use any type of data asdata。
You can use it like this:
MyClass<int> obj1(5); // int type
MyClass<double> obj2(3.14); // double type
Templates can accept multiple parameters, for example:
template <typename T, typename U>
class Pair {
private:
T first;
U second;
public:
Pair(T first, U second) : first(first), second(second) {}
T getFirst() { return first; }
U getSecond() { return second; }
};
Such a template class can store two different types of data:
Pair<int, double> pair1(1, 3.14);
Template specialization allows us to specifically define templates of specific types. For example:
template <>
class MyClass<int> {
public:
MyClass(int data) { /* Specialized behavior */ }
};
This code is specializedMyClassrightintThe behavior of a type that makes it different from other types.
Templates can also accept non-type parameters, such as constant values:
template <typename T, int Size>
class Array {
private:
T data[Size];
public:
int getSize() const { return Size; }
};
here,SizeIs a non-type parameter indicating the size of the array.
Usage example:
Array<int, 10> arr; // Create an int type array with a size of 10
C++ templates are powerful, making code more versatile and reducing duplication. Understanding how to use technology such as function templates, category templates, and template specialization will greatly enhance the flexibility and performance of programming.
In C++, when two classes depend on each other and need to reference each other's members at the same time, directly in their respective.hin file#includeThe other party's definition will cause a circular reference problem, resulting in failure to compile. The solution is to use "forward declaration" to avoid circular references.
.hThe file only declares the existence of the other party's category and does not directly include the other party's header file..cppThe file contains each other's header files, allowing the compiler to obtain the complete class definition.// ClassA.h
#ifndef CLASSA_H
#define CLASSA_H
// Forward declaration ClassB
class ClassB;
class ClassA {
public:
ClassA();
void setB(ClassB* b); // Set the pointer to ClassB
void showBData(); // Display ClassB data
private:
ClassB* b; // pointer to ClassB
};
#endif
// ClassB.h
#ifndef CLASSB_H
#define CLASSB_H
// Forward declaration ClassA
class ClassA;
class ClassB {
public:
ClassB(int data);
int getData(); // Get data
void setA(ClassA* a); // Set the pointer to ClassA
void showAInfo(); // Display ClassA information
private:
int data;
ClassA* a; // pointer to ClassA
};
#endif
#include "ClassA.h"
#include "ClassB.h"
#include <iostream>
ClassA::ClassA() : b(nullptr) {}
void ClassA::setB(ClassB* b) {
this->b = b;
}
void ClassA::showBData() {
if (b != nullptr) {
std::cout << "ClassB data: " << b->getData() << std::endl;
}
}
#include "ClassB.h"
#include "ClassA.h"
#include <iostream>
ClassB::ClassB(int data) : data(data), a(nullptr) {}
int ClassB::getData() {
return data;
}
void ClassB::setA(ClassA* a) {
this->a = a;
}
void ClassB::showAInfo() {
if (a != nullptr) {
a->showBData();
}
}
ClassA.handClassB.h, we only use forward declarations to indicate the existence of the other class, so as to avoid circular references..cppThe archive contains the header file of the other party, ensuring that the complete category definition of the other party is obtained when using the indicator.In C++,friendKeywords can be used on functions or classes to allow other functions or classes to access private and protected members of the class. Such a design allows external functions or classes to operate without violating the encapsulation principle.
A Friend function is an external function that is granted access to the private and protected members of another class. When declared inside a category, end withfriendJust modify the keywords.
Examples are as follows:
#include <iostream>
using namespace std;
class Box {
private:
double width;
public:
Box(double w) : width(w) {}
//Declare friend function
friend void showWidth(Box &b);
};
//Friend function definition, can access private members of Box class
void showWidth(Box &b) {
cout << "Box width: " << b.width << endl;
}
int main() {
Box box(10.5);
showWidth(box); // Access private member width
return 0;
}
In this example,showWidthAlthough the function is an ordinary function outside the Box category, it can still access the private members of the Box category because it is declared as a friend function.width。
The Friend class allows one class to access all members of another class. Such a setup is useful when categories need to work closely together, but should be used with caution to avoid exposing too many internal details.
Examples are as follows:
#include <iostream>
using namespace std;
class Square; // forward declaration
class Rectangle {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
// Declare the Square category as friend
friend class Square;
};
class Square {
public:
double areaOfRectangle(Rectangle &rect) {
return rect.width * rect.height;
}
};
int main() {
Rectangle rect(5.0, 3.0);
Square square;
cout << "Area of rectangle: " << square.areaOfRectangle(rect) << endl;
return 0;
}
In this example, the Square class is declared as a friend class of the Rectangle class, so the member functions in the Square class can directly access the private members of the Rectangle class.widthandheight。
Be careful when using friend functions and friend classes in C++. Excessive use will destroy the encapsulation of the class. Therefore, the friend keyword is usually only used when designing classes or functions that require close cooperation.
In C++, the most standard and recommended way to read a text file line-by-line is to use the file streaming class from the standard librarystd::ifstreamCooperatestd::getlinefunction.
std::ifstreamResponsible for opening and managing file streaming, andstd::getlineis responsible for reading an entire line of text from the stream (until a newline character is encountered\n) and store it instd::stringin the object.
The following is a complete C++ example that demonstrates how to read line by line a file namedexample.txtfile contents.
#include <iostream>
#include <fstream> // Include file streaming library
#include <string> // Include string category
using namespace std;
void read_file_line_by_line(const string& filename)
{
// 1. Create std::ifstream object
//Try to open the specified file.
ifstream input_file(filename);
// 2. Check whether the file is opened successfully
if (!input_file.is_open())
{
cerr << "Error: Unable to open file" << filename << endl;
return;
}
string line;
int line_number = 1;
// 3. Use std::getline function to read line by line
// The loop condition (getline(stream, string)) returns true each time the read is successful.
// When end of file (EOF) is reached or an error occurs, return false and the loop ends.
while (getline(input_file, line))
{
cout << "Line " << line_number << ": " << line << endl;
line_number++;
}
// 4. Close file streaming
// When the input_file object exceeds its scope, the destructor will automatically close the file.
// But calling close() explicitly is also acceptable.
input_file.close();
cout << "File reading completed." << endl;
}
int main()
{
read_file_line_by_line("example.txt");
return 0;
}
std::ifstream: inherited fromstd::istream, specifically used to process file input streams. at build time (or usingopen()function) will try to open the file.input_file.is_open(): This is standard error checking. If the file does not exist or the program does not have read permission, this function will returnfalse。std::getline(stream, string):
input_file) to read data.std::stringobjects, such asline)middle.\n,thereforelineThe variable does not contain newline characters.true。std::ifstreamobject (input_file) is destroyed, it will automatically call its destructor to close the underlying file control code. This is a reliable resource management method (RAII, Resource Acquisition Is Initialization).In C++, converting a data structure (e.g. fromstd::vector<std::string>To write the file line by line (tokens read in) and ensure that each column (token) maintains a fixed width alignment in the line, you need to use **std::ofstream** Use **I/O Stream Manipulators** to control the output format.
The main format control tools are:
std::setw(width): Set the minimum width of the next output field.std::left / std::right: Set the alignment of text in the column (left or right).The following is a C++ example of how to convert a two-dimensional data structure containing multiple fields (usingstd::vector<std::vector<std::string>>Simulate) and write the file, making sure that each token field has a fixed width of 15 characters and is left aligned.
#include <iostream>
#include <fstream> // Include file output stream
#include <string>
#include <vector>
#include <iomanip> // Include I/O stream manipulator (setw, left/right)
using namespace std;
// Simulate a two-dimensional data structure, each row contains multiple fields (tokens)
using TableData = vector<vector<string>>;
void write_aligned_data(const string& filename, const TableData& data, int column_width)
{
// 1. Create std::ofstream object and open the file
ofstream output_file(filename);
// 2. Check whether the file is opened successfully
if (!output_file.is_open())
{
cerr << "Error: Unable to open file " << filename << " for writing." << endl;
return;
}
//Set global alignment: left-aligned (L-Justified)
output_file << left;
// 3. Write data line by line
for (const auto& row : data)
{
// 4. Write token by token and set the width
for (const auto& token : row)
{
// setw(width) only affects the next output item immediately following it
output_file << setw(column_width) << token;
}
// 5. Insert a newline character after the end of the line to start a new line
output_file << "\n";
}
// 6. Close file streaming
output_file.close();
cout << "Data has been successfully written to the file: " << filename << endl;
}
int main()
{
//Sample data: contains four rows, each row has three fields
TableData data = {
{"Name", "Item", "Price"},
{"Alice", "Book", "19.99"},
{"BobJohnson", "PenSet", "4.50"},
{"Charlie", "Notebook", "800.75"}
};
const int COLUMN_WIDTH = 15; // Define the width of each column
write_aligned_data("output_aligned.txt", data, COLUMN_WIDTH);
return 0;
}
std::ofstream: File output streaming category. Used to write data into files.#include <iomanip>: This header file must be included to use the I/O stream manipulator.output_file << left;:
rightorinternalcover.output_file << setw(column_width) << token;:
setw(width): Set the minimum width of the data to be output next. If the length of the output string is less than the set width, it will be padded with blank characters.setwOnly valid for the next output operation immediately following it, so it must be called once before each output token.In .NET C++ (or more commonly C++/CLI) projects, reading and parsing HTML tables in files usually requires the use of an external HTML parsing library, because the standard .NET framework and C++ themselves do not have built-in powerful HTML DOM parsing capabilities. A common and efficient option is to use a library in C# or another .NET language and then reference it in C++/CLI.
For C++/CLI projects, the most practical and recommended approach is to useHtml Agility Pack(HAP), a very popular .NET HTML parser. Although HAP is written in C#, it can be used seamlessly as a reference in any .NET language, including C++/CLI.
HtmlAgilityPack。The following is a C++/CLI code snippet that demonstrates how to read a local HTML file and parse the first table in it (<table>) content:
#using <System.dll>
#using <System.Xml.dll>
#using <HtmlAgilityPack.dll> // Make sure the reference is included
using namespace System;
using namespace System::IO;
using namespace HtmlAgilityPack;
void ParseHtmlTable(String^ filePath)
{
// Check if the file exists
if (!File::Exists(filePath))
{
Console::WriteLine("Error: File does not exist.");
return;
}
// 1. Load HTML file
HtmlDocument^ doc = gcnew HtmlDocument();
try
{
//Load HTML from file
doc->Load(filePath);
}
catch (Exception^ ex)
{
Console::WriteLine("An error occurred while loading the file: " + ex->Message);
return;
}
// 2. Select the first <table> node
HtmlNode^ table = doc->DocumentNode->SelectSingleNode("//table");
if (table != nullptr)
{
Console::WriteLine("Find the HTML table and start parsing...");
// 3. Select all <tr> (table column) nodes
HtmlNodeCollection^ rows = table->SelectNodes(".//tr");
if (rows != nullptr)
{
for each (HtmlNode^ row in rows)
{
// 4. Select the <td> or <th> (cell) node
// Use the | operator to select <td> or <th>
HtmlNodeCollection^ cells = row->SelectNodes("td | th");
if (cells != nullptr)
{
String^ rowData = "";
for each (HtmlNode^ cell in cells)
{
// Get the internal text of the cell and remove the leading and trailing blanks
rowData += cell->InnerText->Trim() + "\t";
}
Console::WriteLine(rowData);
}
}
}
else
{
Console::WriteLine("<tr> tag not found in table.");
}
}
else
{
Console::WriteLine("<table> tag not found in file.");
}
}
int main(array<String^>^ args)
{
// Please replace "your_html_file.html" with your actual file path
String^ htmlFilePath = "C:\\path\\to\\your_html_file.html";
ParseHtmlTable(htmlFilePath);
return 0;
}
doc->Load(filePath): Read local HTML files into HAP's DOM structure.SelectSingleNode("//table"): Use XPath expression to select the first one in the file<table>element.SelectNodes(".//tr"): Select the current node (<table>) all under<tr>element.SelectNodes("td | th"):Select<tr>All under the node<td>or<th>element.cell->InnerText: Get the plain text of the cell content, and HTML tags will be automatically removed.gcnewand^:This is the syntax used by C++/CLI to create and manage .NET objects (managed by the CLR garbage collection mechanism).HttpListenerClass allows you to create a simple, self-hosted HTTP server in a C++/CLI application.
Create a C++/CLI project in Visual Studio (e.g. CLR Console Application) and make sure it is referencedSystem.dll。
The following is usedHttpListenerC++/CLI code to create a simple API server and handle GET requests.
#using <System.dll>
using namespace System;
using namespace System::Net;
using namespace System::Threading::Tasks;
using namespace System::Text;
// Function to handle incoming HTTP requests
void HandleRequest(HttpListenerContext^ context)
{
HttpListenerRequest^ request = context->Request;
HttpListenerResponse^ response = context->Response;
//Default response settings
response->ContentType = "application/json; charset=utf-8";
String^ responseString = "";
response->StatusCode = 200; // Default is OK
// Check the requested path and method
String^ url = request->RawUrl->ToLower();
if (url == "/api/status" && request->HttpMethod == "GET")
{
// Handle GET /api/status request
responseString = "{\"status\": \"Server Running\", \"language\": \"C++/CLI\"}";
}
else
{
// Handle other undefined requests
response->StatusCode = 404; // Not Found
responseString = "{\"error\": \"404 Not Found\", \"path\": \"" + url + "\"}";
}
// Convert string response to bytes and write to output stream
array<Byte>^ buffer = Encoding::UTF8->GetBytes(responseString);
response->ContentLength64 = buffer->Length;
try
{
response->OutputStream->Write(buffer, 0, buffer->Length);
response->OutputStream->Close();
}
catch (Exception^)
{
// Ignore write errors, usually client disconnects
}
}
// Function to start HttpListener
void StartListener(String^ prefix)
{
HttpListener^ listener = gcnew HttpListener();
try
{
listener->Prefixes->Add(prefix);
listener->Start();
Console::WriteLine("C++/CLI API Server started, listening: {0}", prefix);
}
catch (Exception^ ex)
{
Console::WriteLine("An error occurred while starting HttpListener. Please confirm whether the permission or address is occupied.");
Console::WriteLine("Error message: {0}", ex->Message);
return;
}
// Asynchronous loop, continue to receive requests
while (listener->IsListening)
{
try
{
// Wait for the next request synchronously
HttpListenerContext^ context = listener->GetContext();
// Use Task to process requests asynchronously to avoid blocking listening loops
Task::Factory->StartNew(gcnew Action<HttpListenerContext^>(&HandleRequest), context);
}
catch (Exception^)
{
// An exception will be thrown when the listener is stopped
break;
}
}
if (listener->IsListening)
{
listener->Close();
}
}
int main(array<String^>^ args)
{
//Set the URL prefix for monitoring
// NOTE: On Windows, administrator rights or using netsh to register the URL namespace may be required.
String^ listeningPrefix = "http://localhost:8080/";
StartListener(listeningPrefix);
Console::WriteLine("Press any key to end the server...");
Console::ReadKey(true);
return 0;
}
On Windows systems, if the code is not run with administrator privileges,HttpListenerAn access-denied exception may be thrown when listening on a specific port. You can register a URL namespace to allow non-administrator accounts to run the server with the following command:
netsh http add urlacl url=http://+:8080/ user=Everyone
inhttp://+:8080/should be replaced with the actual prefix used in your code.
In ASP.NET Core, the standard project type for creating an HTTP API server is Web API. Latest .NET version (.NET 6 and above) recommendedMinimal APIsto quickly and lightweightly create API endpoints.
Minimal APIs combine startup logic (Startup) and routing definitions (Routing) into a single file using minimal files and lines of codeProgram.csmiddle.
To create a new Minimal API project, you can use the .NET CLI (Command Line Interface):
dotnet new web -n MinimalApiServer
cd MinimalApiServer
The following is the Minimal API server core fileProgram.csfull content. It defines server startup, middleware, and two API endpoints (one GET, one POST).
// 1. Create a WebApplication instance (replacing the traditional Startup category)
var builder = WebApplication.CreateBuilder(args);
// 2. Register service (Service Configuration)
//Here you can add database connection, verification services, etc.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); // Enable Swagger/OpenAPI support
var app = builder.Build();
// 3. Configure HTTP request pipeline (Middleware Configuration)
// In the development environment, enable Swagger UI for testing
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// Enable HTTPS redirection (recommended for production environments)
// app.UseHttpsRedirection();
// 4. Define API endpoint (Endpoint Definition)
// Entity class used for POST requests
public record Product(int Id, string Name, decimal Price);
// GET request endpoint: /api/hello
app.MapGet("/api/hello", () =>
{
return Results.Ok(new { message = "Hello from ASP.NET Core Minimal API!", timestamp = DateTime.Now });
});
// GET request endpoint: /api/products/{id}
app.MapGet("/api/products/{id}", (int id) =>
{
// Assume querying products from the database
if (id == 1)
{
return Results.Ok(new Product(1, "laptop", 1200.00m));
}
return Results.NotFound(new { error = $"Product ID {id} not found" });
});
// POST request endpoint: /api/products
app.MapPost("/api/products", (Product product) =>
{
// ASP.NET Core will automatically deserialize the JSON request body into a Product entity
Console.WriteLine($"Received new product: {product.Name} (ID: {product.Id})");
//In actual application, the database addition operation will be performed here.
//Return 201 Created status code
return Results.Created($"/api/products/{product.Id}", product);
});
// 5. Start the application and start listening for HTTP requests
app.Run();
dotnet run。http://localhost:5000orhttps://localhost:7000run./api/hello (GET)。/swaggerPath to view Swagger UI for testing all defined API endpoints.app.UseSwagger()、app.UseHttpsRedirection()Etc., these components constitute the request processing pipeline in sequence. Every request flows through these middlewares.app.MapPostIn the example, when the client sends JSON data, ASP.NET Core will automatically convert (deserialize) it into C#ProductRecord.vcpkg is not installed through the installation file, but directly copies the source code from GitHub to local. It is recommended to place it in the root directory of the disk (such asC:\vcpkg) to avoid paths that are too long or contain spaces. Please open the terminal (CMD or PowerShell) and execute:
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
After downloading, you need to execute the script to compile the executable file of vcpkg, which will generatevcpkg.exe:
.\bootstrap-vcpkg.bat./bootstrap-vcpkg.shThis step allows development tools (such as Visual Studio) to automatically recognize the packages installed by vcpkg:
implement.\vcpkg integrate install. After completion, the new project you create in VS can be directly#includeKit, no need to manually set the path.
When executing CMake configuration, add the following parameters to link to the vcpkg toolchain file:
-DCMAKE_TOOLCHAIN_FILE=[vcpkg path]/scripts/buildsystems/vcpkg.cmake
| instruction | illustrate | example |
|---|---|---|
search |
Search available packages | vcpkg search libuv |
install |
Install specified packages | vcpkg install libuv:x64-windows |
list |
List installed packages | vcpkg list |
update |
Check for package version updates | vcpkg update |
In order to facilitate the use of vcpkg in any path, it is recommended to add the vcpkg folder path to the systemPATHin environment variables. In addition, if you want to install the 64-bit package by default, you can add an environment variableVCPKG_DEFAULT_TRIPLETand set its value tox64-windows。
Before using vcpkg on Windows, make sure it is installedVisual Studio 2015 or newer, and check the "Desktop development using C++" workload (including English language pack), otherwise errors may occur when compiling the package.
In C++/CLI,MessageBox::ShowIt is a static method used to pop up a dialog box. The most complete call method includes: message content, title, button type, icon and default button.
using namespace System::Windows::Forms;
//The simplest display
MessageBox::Show("Operation completed");
//Full parameter version
DialogResult result = MessageBox::Show(
"Are you sure you want to delete this file?", // Message content (Text)
"Confirm deletion", // window title (Caption)
MessageBoxButtons::YesNo, // Button combination
MessageBoxIcon::Warning, // Prompt icon
MessageBoxDefaultButton::Button2 // Default focus is on the second button (No)
);
Must be checked when a button contains multiple options such as Yes/No or OK/CancelDialogResultto determine the subsequent logic.
if (result == DialogResult::Yes) {
//Execute deletion logic
} else {
//Cancel operation
}
| category | Common options | illustrate |
|---|---|---|
| MessageBoxButtons | OK, OKCancel, YesNo, YesNoCancel | Defines which buttons appear below the dialog box. |
| MessageBoxIcon | Information, Warning, Error, Question | Define the icon and system sound effects displayed on the left. |
| DialogResult | OK, Cancel, Yes, No | ShowThe return value of the method represents which key the user pressed. |
becauseMessageBox::ShowReceived is .NETSystem::String^, if you have native C++ data, you need to convert it.
#include <string>
#include <msclr/marshal_cppstd.h>
// Display std::string in MessageBox
std::string cpp_str = "Core Error";
MessageBox::Show(msclr::interop::marshal_as<System::String^>(cpp_str));
//Format the float and display it
float dist = 1.23456f;
MessageBox::Show("The distance is: " + dist.ToString("F2")); // Display "The distance is: 1.23"
MessageBoxButtons::OK。using namespace System;andusing namespace System::Windows::Forms;, possibly with otherMessageBoxDefinition conflict, it is recommended to use the full nameSystem::Windows::Forms::MessageBox::Show(...)。System::Windows::Forms::MessageBoxis designed to display "notifications" or "warnings" and obtain user decisions via standard buttons. It does not have the function of dynamically inserting control items. If you need to enter text, the standard approach is to inheritSystem::Windows::Forms::FormCreate a custom dialog box.
This is a simple, reusable category that contains labels, text boxes, and OK buttons.
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
public ref class CustomInputBox : public Form {
public:
TextBox^ txtInput;
Button^ btnOK;
Label^ lblPrompt;
CustomInputBox(String^ title, String^ prompt) {
//Set basic properties of the form
this->Text = title;
this->Size = System::Drawing::Size(300, 150);
this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
this->StartPosition = FormStartPosition::CenterParent;
this->MaximizeBox = false;
this->MinimizeBox = false;
// Prompt text
lblPrompt = gcnew Label();
lblPrompt->Text = prompt;
lblPrompt->Location = Point(15, 15);
lblPrompt->Size = System::Drawing::Size(250, 20);
// input box
txtInput = gcnew TextBox();
txtInput->Location = Point(15, 40);
txtInput->Size = System::Drawing::Size(250, 20);
// OK button
btnOK = gcnew Button();
btnOK->Text = "OK";
btnOK->DialogResult = System::Windows::Forms::DialogResult::OK;
btnOK->Location = Point(190, 75);
// Add controls
this->Controls->Add(lblPrompt);
this->Controls->Add(txtInput);
this->Controls->Add(btnOK);
//Set the default button (pressing Enter is equivalent to clicking OK)
this->AcceptButton = btnOK;
}
};
useShowDialog()The method opens the window in forced response mode and checks whether the return value isOK。
void OnButtonClick() {
CustomInputBox^ ibox = gcnew CustomInputBox("System input", "Please enter the file name:");
if (ibox->ShowDialog() == System::Windows::Forms::DialogResult::OK) {
String^ userInput = ibox->txtInput->Text;
if (!String::IsNullOrWhiteSpace(userInput)) {
// Process the string entered by the user
MessageBox::Show("You entered: " + userInput);
}
}
}
| plan | Implementation complexity | advantage | shortcoming |
|---|---|---|---|
| Custom Form | middle | Full control over the layout and the ability to add validation logic (such as limited numbers). | More interface code needs to be written. |
| VB Interaction | Low | One line of code completed. | Need to quoteMicrosoft.VisualBasic, the style is fixed and cannot be adjusted. |
| Win32 API | high | No .NET environment required. | Developing in C++/CLI is extremely trivial and difficult to maintain. |
delete ibox;Or make sure it releases resources correctly after the scope ends.ShowDialog()rather thanShow(), this ensures that the user must close the input window before operating the main window, and can directly obtainDialogResult。PictureBox displays a red cross, indicating that theOnPaintAn exception occurred during execution,
However, .NET swallows this exception by default and will not show it in the general log or interruption points, making it difficult to debug.
| reason | illustrate |
|---|---|
| Bitmap has been Disposed | PictureBox still holds a reference to the Bitmap, and the released resources are accessed during Paint. |
| Source Stream is closed | After using Stream to create a Bitmap and then closing the Stream, the Bitmap data will become invalid. |
| Cross-thread access | The background thread directly modifies or assigns Bitmap, which conflicts with the UI thread. |
| GDI+ resource exhaustion | A large number of Bitmaps are not Disposed, resulting in insufficient GDI+ memory |
| Exception message | root cause | Solution direction |
|---|---|---|
| ArgumentException: Parameter is not valid | Bitmap has been Disposed or Stream has been closed | Deep copy Bitmap, does not rely on Stream |
| InvalidOperationException: object is in use elsewhere | Access the same Bitmap simultaneously across threads | Add lock, or Invoke back to the UI thread |
| OutOfMemoryException | GDI+ resources are exhausted or the image format is not supported | Dispose the old Bitmap promptly and check the image source |
| ExternalException: A generic error occurred in GDI+ | The file or stream corresponding to the Bitmap no longer exists | Ensure that the source is still valid during the Bitmap lifetime |
Since the red cross problem may not occur often, it is recommended to proceed in order:
OnPaint,
Use try/catch to catch exceptions and output them toDebug.WriteLine,
execute after capturethis.Image = nullAvoid persistent red crosses.Environment.StackTrace, find out who released the resource at what point in time.ImageSet to null and then Dispose.All image changing operations are performed through this mode to ensure thread safety and correct Dispose order:
// C++/CLI
void SafeUpdateImage(Bitmap^ newBmp) {
if (pictureBox1->InvokeRequired) {
pictureBox1->Invoke(gcnew Action<Bitmap^>(
this, &YourClass::SafeUpdateImage), newBmp);
return;
}
Bitmap^ old = safe_cast<Bitmap^>(pictureBox1->Image);
pictureBox1->Image = newBmp; // Change to the new picture first
if (old != nullptr) old->Dispose(); // Dispose the old picture again
}
// Error: bitmap invalid after stream is closed
using (var stream = new FileStream(path, FileMode.Open)) {
pictureBox1.Image = new Bitmap(stream);
}
// Correct: deep copy, does not rely on stream
Bitmap loaded;
using (var stream = new FileStream(path, FileMode.Open))
using (var tmp = new Bitmap(stream)) {
loaded = new Bitmap(tmp);
}
pictureBox1.Image = loaded;
| Check items | Confirmation method |
|---|---|
| Whether the Bitmap is Disposed elsewhere | Unifiedly change images through SafeUpdateImage and record StackTrace |
| Whether the source Stream is closed | Use deep copy insteadnew Bitmap(tmp) |
| Whether to access across threads | Check InvokeRequired when changing images, always Invoke back to the UI execution thread |
| Does the red cross appear immediately or after a while? | If it appears immediately, it may be a source problem; after a while, it may be a Dispose timing problem. |
Peripheral control programs are applications used to communicate and operate external hardware devices (such as printers, scanners, motors, PLCs, sensors, etc.) connected to the computer or host.
| language | Applicable situations | Remark |
|---|---|---|
| Python | Rapid development, test automation | Applicable to Serial, USB HID |
| C/C++ | Embedded control and driver development | Access to low-level memory and hardware |
| C# | Windows UI + Control Device | Suitable for COM Port and USB communication |
| Java | Cross-platform control | Less commonly used in low-end devices |
import serial
ser = serial.Serial('COM3', 9600, timeout=1)
ser.write(b'ON\n') # Send control commands
response = ser.readline()
print("Device response:", response.decode())
ser.close()
SerialPort port = new SerialPort("COM4", 9600);
port.Open();
port.WriteLine("MOVE 100");
string response = port.ReadLine();
Console.WriteLine("Response: " + response);
port.Close();
libusb(C)、pyusb(Python)、HidSharp(C#) and other function librariesimport socket
s = socket.socket()
s.connect(('192.168.1.100', 5000))
s.sendall(b'START\n')
data = s.recv(1024)
print("Response:", data.decode())
s.close()
Peripheral control program development requires selecting the appropriate language and function library based on the device's interface and protocol, and combining serial, USB, network and other communication methods, which can be widely used in various automation and industrial control fields.
// build.gradle
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
//Java call scan screen
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setPrompt("Please scan the barcode");
integrator.setBeepEnabled(true);
integrator.setOrientationLocked(false);
integrator.initiateScan();
//onActivityResult receives the result
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if(result != null) {
if(result.getContents() != null) {
String barcode = result.getContents();
Log.d("Barcode content", barcode);
}
}
}
<script src="https://unpkg.com/[email protected]/dist/quagga.min.js"></script>
<script>
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector('#scanner')
},
decoder: {
readers: ["code_128_reader", "ean_reader", "upc_reader"]
}
}, function(err) {
if (!err) {
Quagga.start();
}
});
Quagga.onDetected(function(result) {
console.log("Barcode content: ", result.codeResult.code);
});
</script>
| platform | Recommended kit | Is it free? |
|---|---|---|
| Android | ZXing / ML Kit | yes |
| Web | QuaggaJS / jsQR | yes |
| Windows | Dynamsoft / ZXing.NET | Dynamsoft for commercial use |
| Python | ZBar / pyzbar | yes |
To develop Barcode Reader, you can choose the appropriate open source package according to the platform. ZXing is the most widely supported choice. QuaggaJS is available for the Web. If you need commercial-level support, you can consider Dynamsoft Barcode SDK.
Barcode readers are essentially devices that simulate keyboard input. When a barcode is scanned, it "outputs" the content in the barcode into a character stream, just like keyboard input.
Therefore, the barcodeCan contain control code (Control Code),butRequires barcode reader and barcode format supportJust fine.
For example, the following format can encode control codes:
Some barcode generators allow embedding special characters, such as:
\x0Dmeans Enter\x03means Ctrl-C^C、[CTRL+C]Special syntax depends on the toolMost professional barcode printers (e.g. Zebra, Honeywell) are preset at the factoryDisable control code output, needs to be enabled through the "Settings barcode" provided by the scanner:
For example in a Windows application:
keydownandCtrlMatching shortcut key processing.Encoding ASCII 3 with Code128:
Input:\x03Hello World
After the barcode is scanned, Ctrl+C will be triggered and "Hello World" will be output.
sudo apt update && sudo apt upgrade -y
sudo apt install -y wget curl unzip zip git ca-certificates
sudo apt install -y openjdk-17-jdk
sudo dpkg -i ~/Downloads/android-studio-*.deb || sudo apt -f install -y
android-studioor decompress.tar.gz:
tar -xzf ~/Downloads/android-studio-*.tar.gz -C ~
~/android-studio/bin/studio.sh
sudo apt install -y android-sdk-platform-tools
adb kill-server
adb start-server
adb devices
sudo dpkg -i ~/Downloads/code_*.deb || sudo apt -f install -y
sudo apt update && sudo apt install -y openjdk-17-jdk unzip git
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
unzip commandlinetools-linux-*_latest.zip -d ~/android-sdk
~/.bashrcor~/.zshrc):
export ANDROID_SDK_ROOT=$HOME/android-sdk
export PATH=$ANDROID_SDK_ROOT/cmdline-tools/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH
sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"
adb devicesSeedeviceThe test is ready to be deployed.adb installor framework CLI (such asflutter run) Deploy the App to the mobile phone.Create a new project in Android Studio, select the "Empty Activity" template, and set the project name and other basic information.
existres/layout/activity_main.xmlA simple user interface designed in the file, for example, containing a button and a text display area:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, World!"
android:layout_marginTop="20dp" />
</LinearLayout>
existMainActivity.java, set the click event of the button to change the content of the text display area:
package com.example.simpleapp;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
TextView textView = findViewById(R.id.textView);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText("You clicked the button!");
}
});
}
}
Click the Run button in Android Studio to test your app on the emulator or a connected physical device. After clicking the button, the text will change to "You clicked the button!".
existAndroidManifest.xmlAdd the following permissions:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(@NonNull Location location) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
Log.d("GPS", "Latitude: " + latitude + ", Longitude: " + longitude);
}
};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
1000, // millisecond interval
1, // Minimum distance (meters)
locationListener);
}
FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
fusedLocationClient.getLastLocation()
.addOnSuccessListener(this, location -> {
if (location != null) {
double lat = location.getLatitude();
double lng = location.getLongitude();
Log.d("GPS", "Lat: " + lat + ", Lng: " + lng);
}
});
}
To implement a voice assistant function like Siri or Hey Google, you need to combine the following components:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET"/>
SpeechRecognizer recognizer = SpeechRecognizer.createSpeechRecognizer(this);
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
recognizer.setRecognitionListener(new RecognitionListener() {
@Override
public void onResults(Bundle results) {
ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
if (matches != null && !matches.isEmpty()) {
String command = matches.get(0).toLowerCase();
if (command.contains("Open camera")) {
// perform operations
}
}
}
//Other necessary overwriting methods are omitted
});
recognizer.startListening(intent);
TextToSpeech tts = new TextToSpeech(this, status -> {
if (status == TextToSpeech.SUCCESS) {
tts.setLanguage(Locale.TAIWAN);
tts.speak("Hello, I'm here.", TextToSpeech.QUEUE_FLUSH, null, null);
}
});
If you want to keep the background and wake it up by voice, you need to use:
RECORD_AUDIOpermissions.The goal of permanent background monitoring is to allow the App to detect voice wake-up words (such as "Hey Assistant") and activate corresponding functions even when the screen is not open.
SpeechRecognizerLong background running.SpeechRecognizerRecognize complete voice commands.public class VoiceService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new NotificationCompat.Builder(this, "voice_channel")
.setContentTitle("Voice assistant is operating")
.setSmallIcon(R.drawable.ic_mic)
.build();
startForeground(1, notification);
//Initialize Hotword detection
startHotwordDetection();
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
NotificationChannel channel = new NotificationChannel("voice_channel",
"Voice Assistant", NotificationManager.IMPORTANCE_LOW);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
Porcupine provides an Android SDK that recognizes custom keywords and operates completely offline.
PorcupineManager porcupineManager = new PorcupineManager.Builder()
.setAccessKey("your key")
.setKeywordPath("hey_assistant.ppn")
.setSensitivity(0.7f)
.build((keywordIndex) -> {
//Call SpeechRecognizer for speech recognition when woken up
startSpeechRecognition();
});
porcupineManager.start();
Intent serviceIntent = new Intent(this, VoiceService.class);
ContextCompat.startForegroundService(this, serviceIntent);
RECORD_AUDIOpermissions.1. Download and install the latest version ofXcode。
2. Open Xcode and go toPreferences > Accounts, sign in with your Apple ID to enable developer features.
3. Install via XcodeCommand Line Toolsto use Swift command-line tools.
1. Open Xcode and select "Create a new Xcode project".
2. Select a suitable application template, e.g.App (iOS/macOS)。
3. Set the project name, Bundle Identifier and language (Swift or Objective-C).
4. Select a UI framework (SwiftUI or UIKit).
1. RegisterApple Developer Program(Annual fee USD $99 required).
2. Set via XcodeApp Store Connectand submit the app.
3. Follow Apple’sApp Store Review GuidelinesMake sure your app meets listing specifications.
iOS development mainly usesXcode, the official integrated development environment (IDE) provided by Apple.
Learning iOS development requires mastering the following basics:
Here are some helpful learning and development resources:
Xcode is an integrated development environment (IDE) provided by Apple for the development of macOS, iOS, watchOS, and tvOS applications.
You can download the latest version of Xcode from the Mac App Store or Apple's official developer website.
Practical tips to improve development efficiency:
Related learning and reference resources:
Swift is Apple’s modern programming language for developing iOS, macOS, watchOS, and tvOS apps.
varandlet?and!Handles the presence or absence of a valueif、switch、for、whilefuncDefinition, supports parameter labels and multiple return valuesclassandstructSwift is not just for the Apple ecosystem, it can also be used for server-side development and cross-platform tools.
Related learning and reference resources:
Objective-C is a C-based object-oriented programming language originally developed by NeXT Corporation and later widely used by Apple for macOS and iOS application development.
Objective-C's syntax combines the features of C and Smalltalk, using the @ symbol to indicate language extensions.
@interfaceand@implementation[object method]@propertyand@synthesizeObjective-C development is primarily done using Apple’s Xcode.
Here are some resources for learning and reference:
GNews is a news aggregation platform developed by Google, designed to help users obtain the latest global news. It integrates content from various news sources and uses artificial intelligence technology to personalize recommendations of news of interest to users.
Users can use this platform by visiting GNews’ website or downloading its app. On the platform, users can select topics of interest, follow specific news sources, and customize news feeds to suit their needs.
GNews is a powerful news aggregation tool that uses artificial intelligence technology to provide users with a personalized news experience. As news information changes rapidly, GNews helps users quickly keep up with world trends and obtain the information they need.
| Tool name | Main features | Applicable scenarios | price |
|---|---|---|---|
| n8n | An open source automated workflow tool that provides highly customizable process design and supports self-built nodes. | Suitable for internal process automation, large-scale automation systems, API integration, etc. | Free and open source, with paid cloud version available. |
| Make | Provides visual workflow construction, supports the integration of multiple third-party applications and services, and emphasizes simplicity and ease of use. | Suitable for workflow automation of small to medium-sized enterprises and rapid integration of various services. | A free plan is available, and a paid plan offers more advanced features based on user needs. |
| Zapier | Supports integration with most applications, is simple and easy to use, and can create triggers and automated workflows. | Suitable for automation in various business areas, especially small businesses and startups. | A free plan is available, and a paid plan provides more features and runs based on user needs. |
Bolt is a fast, lightweight AI development framework that focuses on providing developers with simple and efficient tools to build applications. Features include:
Cursor is an editor tool designed specifically for AI program development, providing intelligent auxiliary code writing and debugging functions. Features include:
v0 is an AI platform based on visual development that allows users to build models and applications through a drag-and-drop interface. Features include:
Codeium is a program editor combined with AI intelligent assistance, focusing on improving the efficiency and accuracy of program development. Features include:
Software engineering is an engineering discipline that develops, operates, and maintains software in a systematic and planned manner. The goal is to build high-quality, maintainable, reliable, and demanding software systems.
Please enter the official name of this project.
Explain the reason for this project, background issues and core issues to be solved, and define clear project goals.
Outline the system functions and overall architecture, which can be paired with the system architecture diagram.
You can attach main screen sketches or wireframes to describe the elements and interactive processes of each screen.
List the main data table structure, fields, correlations, etc.
List external systems, APIs, or other software components that need to be integrated.
List potential risks, constraints (such as budget, manpower, technology, etc.).
Related document links, reference materials, term definitions, etc.
Design Patterns are a set of proven software design solutions that are mainly used in object-oriented programming to solve recurring design problems in specific situations.
Version Control is a system that manages file change history. It is widely used in software development, allowing multiple developers to collaborate at the same time and retaining a complete record of each change.
git init:Initialize the version librarygit clone [url]:Copy remote projectgit add [file]:Add changes to the staging areagit commit -m "message": Submit changesgit push: Push changes to the remote repositorygit pull: Get and merge remote changesgit branch: View or create branchesgit merge: merge branchesGit is a decentralized version control system developed by Linus Torvalds (the father of Linux) in 2005 for tracking code changes, collaborative development, and version management. It is the most widely used version control tool today and is used in personal development, team projects and open source communities.
git --versionto confirm the installation was successful.When using Git for the first time, you need to set developer information:
git config --global user.name "your name" git config --global user.email "Your [email protected]"
git init # Initialize local repository git clone URL # Copy the remote repository git add . # Add changes to the staging area git commit -m "description" # Create a commit git status # View current status git log # View commit records git branch # View branch list git checkout branch name # switch branches git merge branch name # Merge the specified branch git push # Push changes to the remote end git pull # Pull updates from the remote end
git initorgit clone)git add)git commit)git push / git pull)If you want to completely discard all local changes that have not been committed (Uncommitted) and have been committed but not yet pushed (Local Commits), and reset the branch to be completely consistent with the remote end, please follow the steps below.
First, make sure your local index is updated with the latest progress on the remote end:
git fetch --all
use--hardThe parameter points the current branch to the corresponding remote branch (assuming your branch is main):
git reset --hard origin/main
git reset --hardOnly files already tracked by Git will be processed. If you have newly created files or folders locally but have not yet git added them, they will remain. To delete them all, usecleaninstruction:
# Execute the test first to see which files will be deleted
git clean -n
# Officially delete files (-f) and directories (-d)
git clean -fd
| Target | Applicable directives |
|---|---|
| Discard all local modifications | git reset --hard origin/<branch_name> |
| Discard only single file modifications | git checkout HEAD -- <file_path> |
| Temporarily save current changes (can be restored later) | git stash |
| Remove all clutter outside of gitignore | git clean -fdx |
git reset --hardis a dangerous operation. After execution, all local uncommitted code willUnable to retrieve。origin/mainReplace with the actual remote branch name you are currently using (e.g.origin/masterororigin/dev)。When a Git merge branch conflicts, the file will be marked as "Unmerged". At this time, Git will insert a conflict mark in the file, and we need to use comparison commands to locate the problem and fix it manually.
Before resolving the conflict, first identify which files are in conflict:
git status
Conflicting files will be listed inUnmerged pathsunder section.
When the file contains conflicting tags, you can use the following methods to view the differences:
git diff<<<<<<<、=======and>>>>>>>mark.git diff --ours <file>git diff --theirs <file>
git diff -p <file>
Git will directly modify the conflict file, the format is as follows:
<<<<<<< HEAD (or your branch name) This is the content of your current branch (Ours) ======= This is the content of the other party's branch (Theirs) >>>>>>> branch_name
For complex conflicts, the text interface is difficult to read. It is recommended to call a dedicated merge tool:
git mergetool
This will start something likeMeld, P4Merge, or VS CodeUsing other tools, compare three versions side-by-side: base version (Base), local version (Local), and remote version (Remote).
After you manually edit the files and decide which code to keep, you must perform the following steps to complete the merge:
<<<<, ====, >>>>mark.git add <file>(Add the resolved file to the temporary storage area).git commit(Complete merge commit).GitHub is a cloud-based version control and collaboration platform mainly used for software development. it usesGitImplement version control, allowing developers to manage a project's source code, track changes, and collaborate with others.
GitHub is suitable for all types of developers, whether they are solo developers, open source communities, or enterprise teams. It can meet the version control and collaboration needs of small projects to large software projects.
git pull --rebasegit pull --rebaseIt pulls the latest changes from the remote branch and re-applies the local changes to the latest remote commit, instead of using traditional merge.
git pull --rebase
--rebase?--rebaseYou can keep your commit history concise, with no redundant merge commits.Suppose you commit some changes locally and there are new commits on the remote end, usegit pull --rebasemeeting:
If a conflict occurs while replaying a local commit, Git will ask for manual conflict resolution:
git addStage resolved files.git rebase --continueContinue replaying the commit.git rebase --abortBack to status quo.git pull --rebaseIt is an important tool for keeping Git submission history clean. It is especially suitable for multi-person collaboration. It can avoid redundant merge submissions and keep the submission record of the code base linear.
To allow other developers to participate in your project, you need to add them as collaborators through the repository's settings page. The following is the operation process:
For personal account repositories, invitees usually have read and write permissions by default; if it is an organization account, more detailed settings can be made:
| Permission level | illustrate |
|---|---|
| Read | Can only read and copy code, suitable for pure viewers. |
| Triage | Can manage Issues and Pull Requests, but cannot write code. |
| Write | Code can be pushed directly to the repository. |
| Maintain | In addition to writing, you can also manage some settings of the repository. |
| Admin | Have full control, including deleting repositories and managing other collaborators. |
This is the most common and intuitive way to delete. Please note that once a repository is deleted, it cannot be restored unless you have a backup.
Username/repository name)。If you have GitHub's command line tool (gh) installed, you can quickly delete it through the terminal:
gh repo delete <username>/<repository name> --confirm
Notice:--confirmThe parameter will skip the confirmation step directly, please use it with caution.
After the remote repository on GitHub is deleted, the local folder on your computer will still exist. To remove completely, delete the folder manually:
rm -rf <folder name>
rd /s /q <folder name>
---
| Operation mode | Scope of influence | Is it recoverable? |
|---|---|---|
| Web interface removal | Only delete data on the GitHub remote server. | No (unless contact support or fork) |
| rm -rf command | Only delete files local to your computer. | No (unless there is a recycle bin) |
| Delete .git folder | Keep the file, but move it back to the normal folder (losing version control functionality). | Yes (re-git init) |
Visual Studio has built-in Git integration function, but you still need to install the Git executable file in the system to perform version control operations (such as Commit, Push, Pull, Merge, etc.).
git --version
git version 2.x.x, means it has been installed; if "Unrecognized git command" is displayed, you need to install Git.Turn on the command prompt and set your username and email:
git config --global user.name "your name" git config --global user.email "Your [email protected]"
This information will be appended to each commit and used to identify the developer.
If using Visual Studio 2022 or newer, you can check during the installation process「Git for Windows」options. In this way, Visual Studio will automatically install and integrate Git without manual configuration.
Once the settings are complete, you can complete the following operations directly in Visual Studio:
Azure DevOps is an integrated development and collaboration platform provided by Microsoft that supports the complete DevOps process from code management, construction, automated testing to deployment. It is suitable for a variety of programming languages and frameworks and can be used for personal projects or large enterprise team development.
If you encounter permission restriction issues when using Azure DevOps Pipelines, Repos or Boards, please first confirm whether your Access Level isBasicor above.
CMake is an open source, cross-platform "Meta-build System". It does not directly compile the program code itself, but automatically generates project files suitable for the current operating system and development environment by reading the configuration file (CMakeLists.txt). For example, on Windows it generates a Visual Studio solution, while on Linux it generates a Makefile or Ninja configuration file.
How to install CMake on different operating systems is as follows:
brew install cmake. You can also download the .dmg file and install it manually.sudo apt update && sudo apt install cmake。CMake is designed to simplify the management of complex software projects. It supports multi-level directory structures, handles dependencies between libraries, and automatically searches for installed libraries on the system. In addition, it also provides testing (CTest) and packaging (CPack) functions, covering the complete life cycle from development to release.
| step | Command example | illustrate |
|---|---|---|
| 1. Configure | cmake -S . -B build |
Read settings and detect system environment. |
| 2. Generate | (automatically executed) | Produce a Makefile or VS project file. |
| 3. Build | cmake --build build |
Call the compiler to do the actual compilation. |
| 4. Install | cmake --install build |
Move the generated executable file to the specified path. |
CMake has excellent cross-architecture support capabilities. In Windows environment, developers can specify the target architecture through parameters, such as using-A x64or-A ARM64. For modern Apple Silicon, CMake supports generating Universal Binaries, allowing programs to run on both Intel and Apple M-series processors.
Traditional Makefiles are difficult to maintain and do not have cross-platform versatility. CMake allows developers to simply write a set of configuration files, and developers around the world can easily open and compile projects in their preferred IDE (such as VS Code, CLion, Xcode). This is why most mainstream open source C++ projects currently use CMake as a standard tool.
Application Deployment is the process of moving a developed application from a development environment to a testing or production environment so that users can actually use it. It ensures that the system can perform stably and reproducibly in different environments.
# Deploy the example using GitHub Actions
name: Deploy Web App
on:
push:
branches: [ "main" ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp .
- name: Deploy to server
run: docker run -d -p 80:80 myapp
Docker (container technology) is an open source platform for automating the deployment, scaling and management of applications. It uses "Containers" to package applications and their dependencies together to ensure consistent execution in different environments.
docker pull [image name]: Download image filedocker run [image name]: Execution containerdocker ps: View executing containersdocker stop [container ID]: Stop the containerdocker rm [container ID]: Delete containerdocker build -t [name] .: Create an image file based on Dockerfiledocker images: View image file list# Use Python image file
FROM python:3.10
# Set working directory
WORKDIR/app
# Copy program files
COPY ./app
#Install dependency packages
RUN pip install -r requirements.txt
#Specify the instructions to be executed when the container starts
CMD ["python", "app.py"]
Docker Compose is a tool that can define multiple container applications. Usedocker-compose.ymlFiles define each service.
version: '3'
services:
web:
build: .
ports:
- "8000:8000"
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: example
Deployment of .NET C++ (C++/CLI or .NET-based C++ applications) on Ubuntu systems needs to be handled separately according to the project type. If you use pure C++/CLI (relying on .NET Framework), you will not be able to execute it directly on Linux and you need to useCross-platform technology for .NET 6/7/8(Such as C++/CLR → C# or using C++/Native with .NET interoperability).
Depending on the nature of the application, deployment can be divided into three scenarios:
Install the .NET SDK and necessary tools in Ubuntu:
sudo apt update
sudo apt install -y dotnet-sdk-8.0
sudo apt install -y build-essential
(Can be replaced according to versiondotnet-sdk-8.0fordotnet-sdk-7.0or other versions)
If you use .NET C# as the main program and call the C++ library:
# Create the main application
dotnet new console -n MyApp
cdMyApp
# Create native function library
mkdir native
cd native
nano add.cpp
add.cpp example:
extern "C" int add(int a, int b) {
return a + b;
}
Compile as a shared function library:
g++ -fPIC -shared -o libadd.so add.cpp
AtProgram.csjoin in:
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("libadd.so", EntryPoint="add")]
public static extern int Add(int a, int b);
static void Main()
{
Console.WriteLine("3 + 5 = " + Add(3, 5));
}
}
Return to the project root directory and execute:
dotnet run
If the output result is3 + 5 = 8, indicating successful deployment.
Programs can be packaged into independently executable deployment files:
dotnet publish -c Release -r linux-x64 --self-contained true
The generated executable file is located inbin/Release/net8.0/linux-x64/publish/。
Applications can be containerized using Docker to run on any Ubuntu system:
# Dockerfile example
FROM mcr.microsoft.com/dotnet/runtime:8.0
WORKDIR/app
COPY ./publish .
COPY ./native/libadd.so /usr/lib/
ENTRYPOINT ["./MyApp"]
Build and execute containers:
docker build -t myapp .
docker run --rm myapp
.soFunction library, used by Windows.dll。LD_LIBRARY_PATH。A feasible way to deploy .NET C++ programs to Ubuntu is usually toC# + C++ native library” structure. If the original program relies on C++/CLI, it needs to be redesigned to support cross-platform .NET. The most recommended way is to use .NET 8 + native C++ modules with Docker to achieve a stable, portable and consistent deployment process.
Module dependency analysis is a software engineering technique used to identify and track external files (such as DLLs, libraries, frameworks) that an application depends on when executing. This is crucial to ensure that the software performs correctly in different environments.
| Purpose | Detailed description |
|---|---|
| troubleshooting | Find program crashes caused by Missing DLL or Version Mismatch. |
| security audit | Identifies whether a program loads unauthorized third-party components or has security vulnerabilities. |
| Performance optimization | Evaluate the impact of too many dependent modules on startup time and memory usage, and remove unnecessary references. |
| Transplantability assessment | Determine whether the software will run on a computer that does not have a specific development environment installed, such as the .NET runtime or VC++ libraries. |
Dependency Walker (commonly known as Depends.exe) is a free tool for analyzing the file structure of Windows applications (such as .exe, .dll, .sys, etc.). It is primarily used to scan any 32-bit or 64-bit Windows module and build a hierarchical tree of all related dependent modules.
| scene | describe |
|---|---|
| System error troubleshooting | Solve system errors such as 0xc000007b (parallel configuration error) or the specified module cannot be found. |
| Software deployment | Developers verify that the installer includes all necessary execution libraries (such as VC++ Redistributable). | Check whether there are different versions of the DLL with the same name in the system path, causing the program to behave abnormally. |
Because Dependency Walker has not been updated for many years, it has poor support for some features of modern Windows 10/11 (such as API Sets or lazy-loaded DLLs), and false red warnings often appear. In this case, the following open source alternative tools are recommended:
Dependencies is an open source, modern dependency analysis tool designed to replace Dependency Walker (Depends.exe), which has been discontinued for many years. It is fully optimized for the system architecture of Windows 10 and Windows 11, and can accurately analyze module associations in modern software environments.
api-ms-win-*Virtual DLLs that begin with will not generate false circular dependency warnings or missing file errors.| characteristic | Dependency Walker (old version) | Dependencies (modern version) |
|---|---|---|
| Windows 10/11 support | Poor (frequent false positives) | Excellent (native support) |
| API Sets Processing | Unrecognized (shown as missing in red) | Correctly mapped to entity DLL |
| development status | Updates stopped (2006) | Under ongoing maintenance (GitHub) |
| core technology | C++ / MFC | C# / WPF (some low-level C++) |
Dependencies is a green installation-free software that can usually be downloaded from GitHublucasg/DependenciesThe repository downloads the compiled Release version. When using it, just drag the .exe or .dll file you want to analyze into the window to start analysis.
The two tools have different design philosophies: Dependency Walker (Depends.exe) includes a dynamic analyzer (Profiler), while modern Dependencies focus on static analysis and API Sets parsing.
If you need to use the "Executor" to troubleshoot DLL errors that only occur when running (such as delayed loading failures or path search problems), you can continue to use Dependency Walker's Profile function:
| advantage | shortcoming |
|---|---|
| CapableDynamic Loading(LoadLibrary) error. | When running on Win10/11, the logs will be filled with a large number of false API-MS-WIN error messages. |
| Can confirm the actual loaded DLL file path (related to the search path order). | If the program fails to start at all due to too many dependencies, Profiler may not be able to capture useful information. |
If you are having too many false errors in Dependency Walker's Profiler and can't see the point, it is recommended to use the following combination instead:
NAME NOT FOUNDrecords, which can tell you exactly where the program failed to find the DLL.Developed by GitHub in partnership with OpenAI, it is currently the most widely used AI coding assistant in the world. It can be embedded directly inVisual Studio Code、JetBrainsIn other popular development environments, it analyzes comments and context to instantly suggest lines of code or entire functions.
This is an independent software developed based on VS Code architecture.AI code editor. Unlike a simple plug-in, Cursor deeply integrates AI into the bottom layer of the editor. It understands the structure (Context) of the entire project and allows developers to talk directly to the entire library to perform global refactoring or bug fixes.
Although Claude is a general-purpose AI, its3.5 Sonnet modelIt is recognized as one of the top choices in terms of program logic, architectural design and debugging capabilities. matchArtifactsFunction, developers can directly preview the generated web page front-end screen or interactive components in the dialog box.
Tabnine attaches great importance toPrivacy and security, suitable for enterprises with high requirements for source code confidentiality. It supports fully localized deployment (Self-hosting), ensures that the code will not be uploaded to the cloud for training, and provides accurate auto-completion functionality.
Development Assistant provided by Amazon Web Services (AWS). In addition to basic code generation, it is especially enhanced withAWS cloud servicesThe integration can help developers quickly write infrastructure as code (IaC) or handle security scans and updates.
AI agent built into the Replit online development environment. It is characterized byAutomated deploymentWith environment construction, users only need to describe the functions of the application, and Agent can automatically create files, install dependent packages, write code, and complete online operation.
Presented by VercelAI for front-end development. Users describe interface requirements through natural language, and v0 will directly generate front-end component code based on React, Tailwind CSS and Shadcn UI, greatly reducing the time of UI stereotypes.
Agentic AI Coding Assistants. The characteristics of this type of tool are its ability to directly access the terminal, read and write files, execute tests, and have the ability to plan tasks independently.
This type of tool is closest to Claude Code and runs directly in your terminal, making it suitable for developers who are accustomed to command line operations.
Such tools integrate agent capabilities into the editor to provide a more intuitive visual development experience.
Such tools usually have more independent operating capabilities and can complete the process from demand analysis to deployment on the web or in a stand-alone environment.
| Tool name | Main interface | Core advantages |
|---|---|---|
| Claude Code | CLI (terminal) | Developed natively by Anthropic, it follows the instructions of Claude 3.5 very closely. |
| Aider | CLI (terminal) | Open source, supports multiple models, and has strong Git automated management. |
| Cursor | IDE (Editor) | The UI has the highest degree of integration and is suitable for developers who don’t like to switch terminals. |
| Cline | VS Code plugin | Open source and completely transparent, you can connect various API Keys by yourself. |
Claude Code is an agent-based command line interface (CLI) tool developed by Anthropic. It runs directly in the developer's terminal and can understand the entire program code library, execute terminal commands, edit files, and assist in processing Git workflow, allowing developers to complete complex programming tasks through natural language.
Claude Code requires Node.js 18+ environment, which can be installed through the following methods:
npm install -g @anthropic-ai/claude-code
claudeNow you can start interactive mode.| Function | Operation mode/shortcut keys |
|---|---|
| Plan Mode | Shift + Tab(Mac/Linux) orAlt + M(Windows). Make a detailed plan before executing. |
| Auto-accept | All changes are automatically accepted without the need to confirm each one. |
| Select file | enter@Quickly search and add specific files as background knowledge. |
| Execute instructions | use!prefix to execute Bash commands directly in the session (for example:!ls -la)。 |
/help: Shows all available commands and instructions./clear: Clear the current conversation history and reset the context space./stats: Display recent Token usage and expense statistics./doctor: Diagnose whether the installation status is normal./compact: Manually compress conversation content to save space.For frequent permission confirmation pop-ups and the need for cross-directory access, optimization settings can be made through startup parameters and built-in commands.
By default, Claude Code will confirm dangerous commands (such as deleting files and executing system commands) one by one. To enter "automation mode" to reduce interference, use the following parameters:
--auto-accept, which causes the tool to automatically execute the suggested instructions without stopping to ask. Note, however, that this is not possible when executing destructive instructions such asrm).claude --auto-accept
/approve-all, which grants temporary full trust for subsequent operations in the current session.For safety reasons, Claude Code will be limited to the project directory where it is started by default. To access external paths, there are three methods:
claude . /path/to/another/project
@And paste the absolute path to the external file, adding its contents into context:Please help me refer to the settings of @/etc/nginx/nginx.conf to modify the current project.
ln -s /path/to/external_dir ./external_dir
In order to facilitate quick startup and bring in these settings in the future, it is recommended that you.bashrcor.zshrc(Cygwin/Linux) Add alias:
alias c='claude --auto-accept . /home/user/common_library'
--auto-acceptLater, Claude may execute shell commands that you have not reviewed. It is recommended to only use it in a trusted project environment.For the needs of fully automated startup (no confirmation) and access to external directories, Claude Code provides special CLI parameters to achieve this. These features are often referred to as "YOLO mode" and are suitable for use in a trusted environment or sandbox.
If you don't want to executels、mkdirOr if you keep clicking OK when editing a file, you can use the following dangerous parameters:
--dangerously-skip-permissions--allow-dangerously-skip-permissions--permission-mode bypassPermissionsuse.By default, Claude can only read and write the directory in which it is started. To access other paths, use--add-dir:
claude --add-dir <path>
claude --add-dir ../another-project --add-dir /var/logIf you want to get it right at once and develop directly between multiple directories without hindrance, you can use a combination of:
claude --dangerously-skip-permissions --add-dir ../library --add-dir ~/shared_configs
| Parameter name | Function description | Applicable situations |
|---|---|---|
--dangerously-skip-permissions |
Skip permission confirmation for all tools (Bash, Read, Write). | Requires extensive automatic refactoring or operation in a sandbox environment. |
--add-dir <path> |
Authorizes Claude to access specific paths outside the current directory. | Cross-project development may require reference to external documentation. |
--permission-mode acceptEdits |
Automatically accept file modifications, but still ask when executing Bash commands. | Relatively safe automation mode. |
--dangerously-skip-permissionsDestructive. If Claude misjudges the command (such as accidentally deleting a file), the system will not intercept it.rootorsudoExecuting this parameter with an identity may be blocked due to security mechanisms. It is recommended to execute it under general user permissions.Cursor is an AI code editor developed based on VS Code. It is not just a plug-in, but it embeds AI capabilities deep into the bottom layer of the editor, allowing it to understand the context of the entire project and have the ability to automatically write, reconstruct, and repair code. Since it inherits VS Code, users can directly import all original settings and extended functions.
Call the AI directly in the code editor:
Cmd + K(Windows forCtrl + K)。Sidebar chat dialog:
Cmd + LOpen the chat window.@Files、@Codebaseor@Webto specify the range of the AI reference.This is Cursor’s most powerful “agent” mode:
Cmd + IStart Composer.| Function name | Setting method | illustrate |
|---|---|---|
| Model switching | Sidebar bottom menu | Switch between Claude 3.5 Sonnet, GPT-4o or Cursor Small. |
| Rules for AI | Settings > General | Customize the AI's response style (for example: always use Traditional Chinese, code must meet specific specifications). |
| Index Project | Settings > Features | Make sure to turn on Local Indexing so that the AI can accurately search the entire project's files. |
Cmd + K, let AI help you write complex Shell instructions.Aider is a terminal-based AI pairing programming tool that supports direct modification of local source code. Before installation, please ensure that the system hasPython 3.8The above versions are the same asGit。
python -m pip install aider-chat
Before starting, the key provided by the AI service provider needs to be set as an environment variable. Aider supports various models such as Anthropic and OpenAI by default:
export ANTHROPIC_API_KEY=your-keysetx ANTHROPIC_API_KEY your-keyAfter the setting is completed, enter in the terminalaiderThis will open the conversation interface.
Aider will only read and modify files that you specify to join the context to save token costs and improve accuracy:
You can directly use natural language to ask Aider to perform tasks, such as: "Help me split this class into two files" or "Fix existing bugs." After performing the modification, Aider will automaticallyGit Commit, and automatically compose a submission message based on the modified content.
| instruction | Function description |
|---|---|
| /undo | Undo the most recent code modification and Git commit performed by AI. |
| /diff | Preview the changes made to the current AI compared to the original version. |
| /chat-mode | Switch between conversation modes (e.g. code mode is used to modify files, ask mode is only used for Q&A). |
| /help | Display the complete list of built-in commands. |
| /exit | Exit the Aider program. |
Aider supports multiple ways to interface with locally executed free and open source models. The most common method is to useOllama、LM StudioorLocalAIWait for the tool to create a local server that is compatible with the OpenAI API specification, and then let Aider point to the server address.
This is currently the simplest and most mainstream localization solution:
ollama pull deepseek-coder-v2(Or choose a model optimized for programs such as Qwen2.5-Coder).--modelThe parameter specifies the Ollama model path.aider --model ollama/deepseek-coder-v2
| parameter | Function description |
|---|---|
| --model | Specify the model name. Local models are usually in the formatollama/<model_name>。 |
| --openai-api-base | If using LM Studio, you need to manually specify the local API URL (such ashttp://localhost:1234/v1)。 |
| --no-stream | If the local inference performance is insufficient and the connection is unstable, you can turn off the streaming output to improve stability. |
Not all models are suitable for use with Aider. The following are local open source models currently recognized by the community as performing better in program development tasks:
Software codes, design documents, user manuals, etc. are all covered by copyright protection. Copyright protection is automatically established upon completion of creation, no registration is required, and unauthorized copying, modification, distribution or commercial use is prohibited.
If the software involves technological innovation or unique algorithms, you can apply for patent protection. Patents are subject to review and approval and protect the inventor's exclusive rights to technical solutions, but pure program logic is usually not protected by patents.
Software names, logos, and brand identities can be registered as trademarks to protect the brand image and market differentiation and prevent others from using it to cause confusion.
Undisclosed programming details, algorithms, database structures, etc. are business secrets. The company should protect it through confidentiality agreements, information management systems, etc.
For example, the Personal Information Law and the Information Security Management Law require users to properly handle personal data and ensure information security during the software development process. Violations may face administrative or criminal liability.
Software development often involves contract contracts, cooperative development contracts, software licensing terms, etc., which clearly define the rights and obligations of both parties, program code ownership, maintenance responsibilities, confidentiality obligations, etc. to avoid legal disputes.
The online operation of software involves network services, electronic payments, online protection of intellectual property rights, etc., and must comply with regulations such as the Electronic Signature Law and the Electronic Transaction Law.
The software code falls within the scope of copyright protection, and developers automatically own the copyright without additional registration. Copyright protection covers source code, design files, user manuals, etc.
If the software involves novelty and technological innovation, it may be possible to apply for patent protection. Examples include unique algorithms or methods of solving technical problems, but pure code logic is usually outside the scope of patent protection.
Software names and logos can be registered as trademarks to distinguish products from different sources and avoid market confusion.
Undisclosed programming details, database structures, and algorithms can be protected through trade secrets. It needs to rely on the company's internal confidentiality agreement and management measures to maintain it.
Software can be released through different licensing models, such as proprietary software, free software, and open source licenses (such as GPL, MIT). Different licensing models affect users' rights to modify and redistribute.
Unauthorized use of another person's code, images or algorithms may constitute copyright infringement. The development process should ensure that the source of the program code is legal to avoid legal disputes.
Intellectual property rights are territorial, but can obtain a certain degree of protection in many countries through international treaties such as the Berne Convention and the TRIPS Agreement.
In 2026, choosing the right software sales platform will depend on your software type and target market. The following are the classifications and characteristics of mainstream platforms:
| demand target | Recommended platform | Core advantages |
|---|---|---|
| Automate global tax processing | Paddle / Lemon Squeezy | Save yourself the trouble of tax declaration in various countries |
| Pursue maximum traffic | Steam / App Store | Ready-made massive user base |
| Quickly build a brand official website | Shopify / SHOPLINE | Highly customized shopping experience |
| Early seed user acquisition | AppSumo | Get cash quickly through promotions |
email: [email protected]