从零开始的c++学习 4:[数组array 与 字符串string]

5 minute read

Published:

记录一下c++学习的步骤 : base on Course ‘CS205 C/C++ Program Design’ in 2021 Fall at Southern University of Science and Technology. | 视频

lecture04 notes

4.1 Arrays 数组

  • 定义: 连续分配的内存,拥有固定长度(长度不可变),元素类型可以任意类型
int num_array1[5]; //uninitialized array, random values 
int num_array2[5] = {0, 1, 2, 3, 4}; //initialization

1 Variable-length arrays

  • 如果长度不是整数常量表达式,则数组将是可变长度

2 Arrays of unknown size

  • 初始化时不指定长度
int num_array[ ] = {1, 2, 3, 4}; // the type of num_array is "array of 4 int"`

//The arguments of a function
float array_sum(float values[], size_t length);
float array_sum(float *values, size_t length);

3 Element accessing

  • No bounds-checking in C/C++. C/C++没有边界检查, 所以要知道数据的长度避免越界
  • Arrays are not objects in C/C++ (different with Java);
  • Arrays can be regarded as addresses
int array1[4] = {9,8,7,6};
int array2[4];
array2 = array1; //error!       //取地址
array2[0] = array1[0]; //okay
array2[1] = array1[1]; //okay
array2[2] = array1[2]; //okay
array2[3] = array1[3]; //okay

4 Multidimensional arrays

  • 在内存中, 多维数组也是顺序存储的,会将多维数组拆成1维数组存放
... - [0][0] - [0][1] - [0][2] - [1][0] - [1][1] - [1][2]-...

... - p+0 - p+1 - p+2 - p+3 - p+4 - p+5 - ...`
int mat[2][3] = \{\{11,12,13\}, \{14,15,16\}\};
for (int r = 0; r < rows; r++){
    for(int c = 0; c < cols; c++)
        cout << mat[r][c] << ",";
        cout << endl;}

// Arrays of unknown bound
void init_2d_array(float mat[][],         //error,必须指定维度
            size_t rows, size_t cols)
void init_2d_array(float mat[][3],
            size_t rows, size_t cols)

5 const Arrays

  • 常量数组
  • 初始化后不可更改,可以参与运算
const float PI = 3.1415926f;
PI += 1.f; // error
const float values[4] = {1.1f, 2.2f, 3.3f, 4.4f};
values[0] = 1.0f; // error

4.2 string

  1. Array-style strings
  2. strings class

1 Array-style strings

  • 数组类型的字符串要多一个字节放 ‘\0’, 避免越界,出现错误结果.
char rabbit[10] = {'p', 'e', 'p', '\0'}

size_t strlen( const char *str );
//返回 字符串长度 ,会在第一个NULL ('\0')停止

2 String literals

  • 可以使用字符串文本更快的操作
  • 这个数据类型也不会越界检查
char name1[] = "Southern University of Science and Technology";
char name2[] = "Southern University of " "Science and Technology";
char name3[] = "ABCD"; //how many bytes for the array?          
                       // 四个字节的字符串,数组的长度是五个字节,还包括多一位的 '\0' 
  • 更多长度/类型的定义
const wchar_t[] s5 = L"ABCD";
const char16_t[] s9 = uABCD"; //since C++11
const char32_t[] s6 = U”ABCD"; //since C++11

3 String manipulation and examination

  • Copy
  • Concatenate
  • Compare
// 1.Copy
char* strcpy( char* dest, const char* src );
//Safer one:
char *strncpy(char *dest, const char *src, size_t count);

//2. Concatenate: appends a copy of src to dest
char *strcat( char *dest, const char *src );
//3.Compare
int strcmp( const char *lhs, const char *rhs );

4 string class

  • 不以null ('\0')结尾的字符串很容易越界,并导致问题
  • 更多字符串类型:
    • Different types of strings
      std::string
      std::wstring
      std::u8string //(C++20)
      std::u16string //(C++11)
      std::u32string //(C++11)
      

4.3 结构体,联合体和枚举类型 structures, Unions and Enumerations

1 structures

  • 结构是由一系列成员组成的类型。
  • 成员按顺序分配

  • padding: 为了对齐内存
    • In order to align the data in memory, some empty bytes will be padded
    • 数据的io为了方便存取,会让数据存在一个区内,将不够的字节用0补齐(8位之类的)

2 Unions

  • 定义 - 一份地址,多个名字
    • 共享同一内存

3 Enumerations

4.4 typedef

  • 创建类型的别名 create an alias for a type
  • 可以控制代码中数据类型的长度,即指定我们需要的数据类型的长度,方便使用

Lab4

Makefile

Makefile is a tool to simplify and organize compilation. Makefile is a set of commands with variable names and targets . You can compile your project(program) or only compile the update files in the project by using Makefile.

  • The name of makefile must be either makefile or Makefile without extension
  • A rule of makefile including three elements: targets, prerequisites and commands.
    • The target is an object file, which is generated by a program. Typically, there is only one per rule.
    • The prerequisites are file names, separated by spaces, as input to create the target.
    • The commands are a series of steps that make carries out. These need to start with a tab character, not spaces.

下面是五个版本的makefile, 层层递进,方便理解

  1. version 1: 相当于手动连接各个文件
    hello: main.cpp printhello.cpp  factorial.cpp
     g++ -o hello main.cpp printhello.cpp  factorial.cpp
    
  2. VERSION 2: ```makefile CXX = g++ TARGET = hello OBJ = main.o printhello.o factorial.o

$(TARGET): $(OBJ) $(CXX) -o $(TARGET) $(OBJ)

将版本1中的g++命令全部用变量形式替换, $()

对应每个文件的编译, 只修改了其中一个文件,就可以不用编译全部文件

如果main文件被修改, 就可以使用make编译

main.o: main.cpp $(CXX) -c main.cpp

printhello.o: printhello.cpp $(CXX) -c printhello.cpp

factorial.o: factorial.cpp $(CXX) -c factorial.cpp


3. VERSION 3
```makefile
CXX = g++
TARGET = hello
OBJ = main.o printhello.o factorial.o

# Flag控制 编译器的选项
# -c 生成目标文件 .o
# -Wall 显示编译警告
CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^
# $@: Object Files
# $^: all the prerequisites files

# This is a model rule, which indicates that all 
# the .o objects depend on the .cpp files
%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@
# $<: the first prerequisite file

# Adding .PHONY to a target will prevent making 
# from confusing the phony target with a file name.
## Because clean is a label not a 
## target, the command make clean 
## can execute the clean part. Only 
## make command can not execute 
## clean part.

.PHONY: clean
clean:
	rm -f *.o $(TARGET)
## 使用`make clean`命令后,删除所有目标文件和可执行文件
  1. VERSION 4 ```makefile CXX = g++ TARGET = hello SRC = $(wildcard *.cpp) OBJ = $(patsubst %.cpp, %.o, $(SRC))

    wildcard: search file

    SRC = … 寻找所有.cpp文件

    patsubst(pattern substitution): replace file

    $(patsubst original pattern, target pattern, file list)

    将原来的cpp文件,替换成.o文件,(保持cpp编译时候的相同文件list)

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ) $(CXX) -o $@ $^

%.o: %.cpp $(CXX) $(CXXFLAGS) $< -o $@

.PHONY: clean clean: rm -f *.o $(TARGET)


5. version 5
```makefile
## 进阶操作,在特定文件夹下搜索文件
## 例如 你的文件排列如下
# --work-dir
# 	--inc : All .h files are in inc
# 	--src : All .cpp files are in src
# 	makefile

SRC_DIR = ./src
SOURCE = $(wildcard  $(SRC_DIR)/*.cpp)
OBJS = $(patsubst %.cpp, %.o, $(SOURCE))
TARGET = hell
INCLUDE = -I./inc 
# -I 在特定文件夹下搜索文件

CXX = g++
CFLAGS = -c -Wall

$(TARGET): $(OBJS)
	$(CXX) -o $@ $(OBJS)

%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@ $(INCLUDE)

.PHONY: clean
clean:
	rm -f $(SRC_DIR)/*.o $(TARGET)