面向对象程序设计——Visual C++
第4章 数组

1、在C++中如何实现两个大小相同的整型数组间的赋值?对字符数组又该如何处理?

在C++中,可以使用循环遍历两个大小相同的整型数组,将一个数组的元素赋值给另一个数组的对应元素。例如:

int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
for (int i = 0; i < 5; i++) {
    arr2[i] = arr1[i];
}

对于字符数组,可以使用字符串库函数strcpy()memcpy()来进行赋值操作。例如:

char str1[10] = "hello";
char str2[10];
strcpy(str2, str1); // 使用strcpy()函数
// 或者
memcpy(str2, str1, sizeof(str1)); // 使用memcpy()函数

需要注意的是,使用字符串库函数进行字符数组的赋值操作时,需要保证目标字符数组有足够的空间来存储源字符数组的内容。

2、在C++中,数组a[3][4]中元素在内存中是按怎样的顺序存放的?

在C++中,多维数组的元素在内存中是按照行优先的顺序存放的,也就是说,对于数组a[3][4],它的元素在内存中的存放顺序是a[0][0]、a[0][1]、a[0][2]、a[0][3]、a[1][0]、a[1][1]、a[1][2]、a[1][3]、a[2][0]、a[2][1]、a[2][2]、a[2][3]。这是因为在内存中,数组的元素是按照一维数组的方式存储的,而多维数组可以看作是一维数组的扩展,因此在存储时也是按照一维数组的方式进行存储的。在行优先的存储方式中,每一行的元素都是连续存储的,因此可以提高访问效率。

3、在C++中,数组作为函数的参数有什么特点?如何将一个数组传递给它?

在C++中,数组作为函数的参数有以下特点:

  1. 数组作为函数参数时,实际上传递的是数组的地址,而不是数组本身。
  2. 数组作为函数参数时,数组的大小必须在函数定义时指定,否则无法正确访问数组元素。
  3. 数组作为函数参数时,可以使用指针或引用来传递。 将一个数组传递给函数的方法有以下几种:
  4. 使用指针传递数组:在函数定义时,将数组参数声明为指针类型,然后将数组的地址作为实参传递给函数。
  5. 使用引用传递数组:在函数定义时,将数组参数声明为引用类型,然后将数组作为实参传递给函数。
  6. 使用数组名传递数组:在函数定义时,将数组参数声明为数组类型,然后将数组名作为实参传递给函数。在函数内部,可以通过下标访问数组元素。

例如,下面是使用指针传递数组的示例代码:

void printArray(int *arr, int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
}
int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    printArray(arr, 5);
    return 0;
}

在上面的代码中,printArray函数接受一个指向int类型的指针和一个整数参数,表示数组的大小。在main函数中,定义了一个包含5个元素的整型数组arr,并将其作为实参传递给printArray函数。在printArray函数内部,使用指针访问数组元素并输出。

4、在C++中应用函数strcpy()和strcat()时,都要注意什么问题?

在C++中应用函数strcpy()和strcat()时,需要注意以下问题:

  1. 目标字符数组必须有足够的空间来存储源字符数组的内容,否则会导致内存溢出和程序崩溃。
  2. 源字符数组必须以空字符'\0'结尾,否则会导致字符串拼接错误。
  3. 在使用strcat()函数时,需要保证目标字符数组已经包含了一个完整的字符串,否则会导致字符串拼接错误。
  4. 在使用strcpy()和strcat()函数时,需要注意字符数组的长度,避免越界访问。
  5. 在使用strcpy()和strcat()函数时,需要注意字符数组的类型,避免类型不匹配导致的编译错误。
  6. 在使用strcpy()和strcat()函数时,需要注意字符数组的编码方式,避免出现乱码问题。

习题

1、判断下列各题是否正确。如果不正确,请说明原因。

(1)数组可以存放许多不同类型的数值。
(2)数组下标可以为float数据类型。
(3)如果初始值表中的初始化值少于数组元素个数,则其余元素自动初始化为零。
(4)初始值表中的初始值的数量可以多余数组元素个数。
(5)将某个数组元素传递给函数并修改该元素值,那么在被调用函数执行结束时仍保留修改后的值。

(1) 不正确。
数组是一组相同类型的数据的集合,不能存放不同类型的数值。
(2) 不正确。
数组下标必须是整数类型,float数据类型无法作为数组下标。
(3) 正确。
如果初始值表中的初始化值少于数组元素个数,则其余元素自动初始化为零。
(4) 不正确。
如果初始值表中的初始值的数量多于数组元素个数,编译器将会报错。
(5) 正确。
将数组元素传递给函数并修改该元素值,可以在被调用函数执行结束时保留修改后的值。

2、设计一个程序,输入数组int a[10]的每一个元素,并求该数组中奇数的个数和平均值以及偶数的个数和平均值。

#include <iostream>

using namespace std;

int countOdd(int a[], int n, double& oddAvg) { // 统计奇数的个数和平均值
    int count = 0;
    double sum = 0;
    for (int i = 0; i < n; i++) {
        if (a[i] % 2 == 1) {
            count++;
            sum += a[i];
        }
    }
    if (count > 0) {
        oddAvg = sum / count;
    }
    return count;
}

int countEven(int a[], int n, double& evenAvg) { // 统计偶数的个数和平均值
    int count = 0;
    double sum = 0;
    for (int i = 0; i < n; i++) {
        if (a[i] % 2 == 0) {
            count++;
            sum += a[i];
        }
    }
    if (count > 0) {
        evenAvg = sum / count;
    }
    return count;
}

int main() {
    int a[10];
    double oddAvg = 0, evenAvg = 0;
    int oddCount, evenCount;
    for (int i = 0; i < 10; i++) {
        cout << "请输入第" << i + 1 << "个数:";
        cin >> a[i];
    }
    oddCount = countOdd(a, 10, oddAvg);
    evenCount = countEven(a, 10, evenAvg);
    cout << "奇数的个数是:" << oddCount << endl;
    cout << "奇数的平均值是:" << oddAvg << endl;
    cout << "偶数的个数是:" << evenCount << endl;
    cout << "偶数的平均值是:" << evenAvg << endl;
    return 0;
}
请输入第1个数:1
请输入第2个数:2
请输入第3个数:3
请输入第4个数:4
请输入第5个数:5
请输入第6个数:6
请输入第7个数:7
请输入第8个数:8
请输入第9个数:9
请输入第10个数:10
奇数的个数是:5
奇数的平均值是:5
偶数的个数是:5
偶数的平均值是:6

3、设计一个程序,输入数组a[10]的每一个元素,再输入一个数x,检查a中是否有值为x的元素,若有,则输出其下标,否则,输出-1。

#include <iostream>
using namespace std;

const int ARRAY_SIZE = 10;

int main() {
    int a[ARRAY_SIZE], x, index = -1;

    // 输入数组a的每一个元素
    cout << "Please input " << ARRAY_SIZE << " elements of the array:" << endl;
    for (int i = 0; i < ARRAY_SIZE; i++) {
        cin >> a[i];
    }

    // 输入数x
    cout << "Please input a number:" << endl;
    cin >> x;

    // 在数组a中查找x的下标
    for (int i = 0; i < ARRAY_SIZE; i++) {
        if (a[i] == x) {
            index = i;
            break;
        }
    }

    // 输出结果
    if (index != -1) {
        cout << "The index of " << x << " is " << index << endl;
    } else {
        cout << "No element equals to " << x << " in the array." << endl;
    }

    return 0;
}

4、求200以内所有素数之和。

#include <iostream>
using namespace std;

const int MAX_NUM = 200;

int main() {
    bool is_prime[MAX_NUM + 1] = {false};
    int sum = 0;

    // 筛选法判断素数
    for (int i = 2; i <= MAX_NUM; i++) {
        if (!is_prime[i]) {
            sum += i;  // 累加素数
            for (int j = i * 2; j <= MAX_NUM; j += i) {
                is_prime[j] = true;
            }
        }
    }

    // 输出结果
    cout << "The sum of prime numbers between 2 and " << MAX_NUM << " is " << sum << endl;

    return 0;
}

5、17人围成圈,依次编号为1~17,从第1号开始报数,报到3的倍数的人离开,一直数下去,直到最后只剩下1人。求此人的编号。

# 使用链表
#include <iostream>
using namespace std;

const int NUM_PEOPLE = 17;
const int MULTIPLE = 3;

// 循环链表结构体定义
struct Node {
    int val;
    Node* next;
};

int main() {
    Node* head = new Node();  // 创建循环链表
    head->val = 1;
    head->next = head;

    // 添加其他节点
    Node* cur = head;
    for (int i = 2; i <= NUM_PEOPLE; i++) {
        Node* node = new Node();
        node->val = i;
        node->next = head;
        cur->next = node;
        cur = node;
    }

    // 模拟报数过程
    Node* prev = cur;
    cur = head;
    while (cur->next != cur) {
        for (int i = 1; i < MULTIPLE; i++) {
            prev = cur;
            cur = cur->next;
        }
        prev->next = cur->next;
        delete cur;
        cur = prev->next;
    }

    // 输出结果
    cout << "The last person's number is " << cur->val << endl;

    return 0;
}
# 使用数组
#include <iostream>
using namespace std;

const int NUM_PEOPLE = 17;
const int MULTIPLE = 3;

int main() {
    bool people[NUM_PEOPLE] = {true};  // 初始化,所有人都在圈内
    int count = 0;  // 计数器,从0开始计数
    int remaining = NUM_PEOPLE;  // 剩余人数,初始为总人数

    // 模拟报数过程
    int i = 0;
    while (remaining > 1) {
        if (people[i]) {
            count++;
            if (count == MULTIPLE) {
                people[i] = false;
                count = 0;
                remaining--;
            }
        }
        i = (i + 1) % NUM_PEOPLE;  // 取余实现循环
    }

    // 输出结果
    for (int i = 0; i < NUM_PEOPLE; i++) {
        if (people[i]) {
            cout << "The last person's number is " << (i + 1) << endl;
            break;
        }
    }

    return 0;
}

6、设计一个程序,利用插入排序算法,对具有n个元素的数组a排序(升序)。

#include <iostream>
using namespace std;

const int MAX_SIZE = 100;  // 定义数组的最大容量

int main() {
    int n;  // 元素个数
    int a[MAX_SIZE];  // 定义数组a
    cout << "Enter the number of elements: ";
    cin >> n;

    // 输入n个元素
    cout << "Enter " << n << " elements:" << endl;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    // 插入排序算法
    for (int i = 1; i < n; i++) {
        int temp = a[i];  // 当前元素
        int j = i - 1;  // 已排序序列的最后一个元素的下标

        // 比较并插入当前元素
        while (j >= 0 && a[j] > temp) {
            a[j + 1] = a[j];
            j--;
        }
        a[j + 1] = temp;
    }

    // 输出排序后的数组
    cout << "The sorted array is:" << endl;
    for (int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    return 0;
}

7、设计一个函数:

void reverse(int a[], int n); 颠倒数组a的前n个元素的顺序。例如对于数组a,假设其初始值为{1,2,3,4,5,6,7,8},则经过函数调用reverse(a,5)之后,数组a变为:{5,4,3,2,1,6,7,8}.

#include <iostream>
using namespace std;

void reverse(int a[], int n) {
    int left = 0;  // 左指针
    int right = n - 1;  // 右指针

    // 双指针交换元素
    while (left < right) {
        int temp = a[left];
        a[left] = a[right];
        a[right] = temp;
        left++;
        right--;
    }
}

int main() {
    int a[] = {1, 2, 3, 4, 5, 6, 7, 8};  // 定义数组a
    int n = 5;  // 前n个元素

    cout << "Before reverse: ";
    for (int i = 0; i < 8; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    reverse(a, n);  // 颠倒前n个元素顺序

    cout << "After reverse: ";
    for (int i = 0; i < 8; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    return 0;
}

8、设计一个函数:

void add(int a[],int b[],int n); 将数组b的前n个元素加到数组a的相应的前n个元素上。

#include <iostream>
using namespace std;

void add(int a[], int b[], int n) {
    for (int i = 0; i < n; i++) {
        a[i] += b[i];  // 将b[i]加到a[i]上
    }
}

int main() {
    int a[] = {1, 2, 3, 4, 5};  // 定义数组a
    int b[] = {5, 4, 3, 2, 1};  // 定义数组b
    int n = 3;  // 前n个元素

    cout << "Before add: ";
    for (int i = 0; i < 5; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    add(a, b, n);  // 将b的前n个元素加到a的前n个元素上

    cout << "After add: ";
    for (int i = 0; i < 5; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    return 0;
}

9、设计一个函数:

bool removeFirst(float a[], int n, float x); 该函数从数组a的查找x。如果找到x,则删除找到的第一个x,该位置以后所有元素依次向前移动一位,并返回true表示删除成功。如果为找到x,则数组不变,并返回false。

#include <iostream>
using namespace std;

bool removeFirst(float a[], int n, float x) {
    int i, j;
    bool found = false;

    // 在数组中查找第一个值为x的元素
    for (i = 0; i < n; i++) {
        if (a[i] == x) {
            found = true;  // 找到了值为x的元素
            break;
        }
    }

    if (!found) {
        return false;  // 没有找到值为x的元素,返回false表示删除失败
    }

    // 找到了值为x的元素,将其删除
    for (j = i; j < n - 1; j++) {
        a[j] = a[j + 1];  // 将元素依次向前移动一位
    }

    return true;  // 删除成功,返回true
}

int main() {
    float a[] = {1.1, 2.2, 3.3, 4.4, 5.5};  // 定义数组a
    int n = 5;  // 数组a的元素个数
    float x = 3.3;  // 要查找的值

    cout << "Before removeFirst: ";
    for (int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    bool success = removeFirst(a, n, x);  // 在数组a中查找并删除第一个值为x的元素

    if (success) {
        n--;  // 删除成功,将数组a的元素个数减1
        cout << "After removeFirst: ";
        for (int i = 0; i < n; i++) {
            cout << a[i] << " ";
        }
        cout << endl;
    } else {
        cout << "Failed to remove " << x << endl;
    }

    return 0;
}

10、求矩阵Amn与Bmn的和矩阵Cmn和差矩阵Dmn。

#include <iostream>
using namespace std;

const int MAX_SIZE = 100;

void matrixSum(int A[][MAX_SIZE], int B[][MAX_SIZE], int C[][MAX_SIZE], int m, int n) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            C[i][j] = A[i][j] + B[i][j];
        }
    }
}

void matrixDiff(int A[][MAX_SIZE], int B[][MAX_SIZE], int D[][MAX_SIZE], int m, int n) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            D[i][j] = A[i][j] - B[i][j];
        }
    }
}

int main() {
    int m, n;
    cout << "请输入矩阵的行数和列数:";
    cin >> m >> n;

    int A[MAX_SIZE][MAX_SIZE], B[MAX_SIZE][MAX_SIZE];
    cout << "请输入矩阵A:" << endl;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cin >> A[i][j];
        }
    }
    cout << "请输入矩阵B:" << endl;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cin >> B[i][j];
        }
    }

    int C[MAX_SIZE][MAX_SIZE], D[MAX_SIZE][MAX_SIZE];
    matrixSum(A, B, C, m, n);
    matrixDiff(A, B, D, m, n);

    cout << "A + B = " << endl;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cout << C[i][j] << " ";
        }
        cout << endl;
    }
    
    cout << "A - B = " << endl;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cout << D[i][j] << " ";
        }
        cout << endl;
    }
    
    return 0;
}

11、设计一个程序,求5*5矩阵两对角线元素之和。

#include<iostream>
using namespace std;

int main() {
    const int size = 5; // 矩阵的大小
    int matrix[size][size]; // 定义二维数组表示矩阵
    int sum = 0; // 两对角线元素之和

    // 输入矩阵元素
    cout << "请输入矩阵元素:" << endl;
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            cin >> matrix[i][j];
        }
    }

    // 计算两对角线元素之和
    for (int i = 0; i < size; i++) {
        sum += matrix[i][i]; // 主对角线上的元素
        sum += matrix[i][size - i - 1]; // 副对角线上的元素
    }

    // 输出结果
    cout << "两对角线元素之和为:" << sum << endl;

    return 0;
}

12、设计一个函数:int strlen(char s[]);

求出字符串s中所包含的字符的个数,并作为函数的返回值(要求不使用库函数strlen())。

#include<iostream>
using namespace std;

int strlen(char s[]) {
    int length = 0; // 字符串的长度
    while (s[length] != '\0') { // 当前字符不是字符串的结尾标志 '\0',就继续往后遍历
        length++; // 字符串长度加1
    }
    return length; // 返回字符串长度
}

int main() {
    char str[] = "Hello, world!"; // 测试字符串
    int length = strlen(str); // 求字符串长度
    cout << "字符串 " << str << " 的长度为:" << length << endl;
    return 0;
}

13、设计一个函数:void strcpy(char s1[], char s2[]);

实现将字符串s2拷贝给字符串s1(要求不要使用库函数strcpy())。

#include<iostream>
using namespace std;

void strcpy(char s1[], char s2[]) {
    int i = 0; // 下标从0开始
    while (s2[i] != '\0') { // 当前字符不是字符串的结尾标志 '\0',就继续往后拷贝
        s1[i] = s2[i]; // 拷贝字符
        i++; // 下标加1
    }
    s1[i] = '\0'; // 拷贝完后在字符串s1的末尾加上结尾标志 '\0'
}

int main() {
    char str1[100]; // 目标字符串
    char str2[] = "Hello, world!"; // 源字符串
    strcpy(str1, str2); // 将源字符串拷贝给目标字符串
    cout << "拷贝后的字符串为:" << str1 << endl;
    return 0;
}

14、设计一个函数:void strcat(char s1[], char s2[]);

实现将字符串s2加到字符串s1的末尾(要求不使用库函数strcat())。

#include<iostream>
using namespace std;

void strcat(char s1[], char s2[]) {
    int i = 0, j = 0; // 下标从0开始
    while (s1[i] != '\0') { // 找到字符串s1的结尾标志 '\0'
        i++; // 下标加1
    }
    while (s2[j] != '\0') { // 将字符串s2的每个字符加到s1的末尾
        s1[i] = s2[j];
        i++;
        j++;
    }
    s1[i] = '\0'; // 在字符串s1的末尾加上结尾标志 '\0'
}

int main() {
    char str1[100] = "Hello"; // 目标字符串
    char str2[] = ", world!"; // 待加入的字符串
    strcat(str1, str2); // 将str2加入str1
    cout << "拼接后的字符串为:" << str1 << endl;
    return 0;
}

实验题

2、完成下列程序,并上机验证其正确性。

该程序重新排列a[N]的元素,使相等的元素放在一起,并保持它们在数组中第一次出现的相对位置。例如:
原数组:2 4 3 5 2 3 4 5 2 3
重排后:2 2 2 4 4 3 3 3 5 5
采用的算法是:统计各不同元素出现的次数(存放在数组c中),并依次记录下这些不同的元素,用数组b[j]标识a的第j个元素是否在前面出现过。最后按各元素重复排列的次数写回到数组a中。

#include <iostream.h>
#define N 10
void main(){
	int a[N],b[N],c[N], i, j, k, j;
	cout<<”输入数组a中的各元素:\n”;
	for(i=0;i<N;i++){
		b[i]=c[i]=i;
		cin>>a[i];
	}
	k=0;
	for(i=0;i<N;i++)
		if(___________){
			a[k]=a[i];
			for(_____;j<N;j++)
				if(a[j]==a[i])
					b[j]=0;c[k]++;
			__________;
		}
	t=N-1;
	for(i=k-1;i>=0;i--)
		for(j=0;__________;j++)
			__________;
	for(i=0;i<N;i++)
		cout<<a[i]<<’\t’;
	cout<<’\n’;
}

3、完成下列程序,并上机验证其正确性。

该程序的功能是输入正整数num,按从小到大的次序输出它的所有的因子。所利用的算法是:i从2开始,如果num能整除i,则可以得到一大一小两个因子,将它们分别放在数组a的两端。

#define N 40
void main(){
	int num, t, i, j=0, k, a[N];
	cout<<”请输入一个正整数:\n”;
	cin>>num;
	i=2, t=num;
	k=N-1;
	a[0]=1, a[N-1]=num;
	while(i<t){
		if(__________){
			t=num/i;
			a[++j]=i;
			if(i<t)
				__________;
		}
		__________;
	}
	cout<<”整数”<<num<<”的因子依次为:”;
	for(i=0;i<=j;i++)cout<<a[i]<<’\t’;
	for(i=k;i<N;i++)cout<<a[i]<<’\t’;
	cout<<’\n’;
}
第一空:num%i==0;
第二空:a[--k]=t
第三空:i++

程序的主要思路是:

  1. 从2开始遍历到num的平方根,如果num能够整除i,则num除以i就是另一个因子。
  2. 将两个因子分别放在数组a的两端。
  3. 输出数组a。 程序的正确性可以通过以下测试验证:
  • 输入:12。输出:1 2 3 4 6 12。
  • 输入:25。输出:1 5 25。
  • 输入:27。输出:1 3 9 27。
  • 输入:35。输出:1 5 7 35。
  • 输入:50。输出:1 2 5 10 25 50。