此 C 程序在工作过程中停止获取输入。我遇到分段错误(核心已转储)。还是不知道问题所在

问题描述 投票:0回答:2

此代码应该获取一个矩阵并通过定义的函数以用户期望的方式对其进行操作。但输入过程无法正常工作,中途崩溃。我从其中一位编译器那里得到了

segmentation fault (core dumped)
。但也不知道这种问题到底出在哪里。确实感谢您的回复,因为我已经开始调试几个小时了。

这是代码:(代码的第一部分与矩阵操作函数相关 - 在某些函数中也可能会采用一些输入 - 但接受输入的整个过程都在主函数中。所以它可能不是需要阅读整个代码)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void print_matrix(int *matrix, int row, int column) 
{
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < column; j++) {
            printf("%d ", matrix[i * column + j]);
        }
        printf("\n");
    }
}

void ravel(int *matrix, int *row_address, int *column_address)
{
    for (int i = 0; i < (*row_address) * (*column_address); i++) {
        printf("%d ", matrix[i]);
    }
    printf("\n");
}

void reshape(int *row_address, int *column_address)
{
    scanf(" %d %d", row_address, column_address);
}

void resize(int **matrix_address, int *row_address, int *column_address)
{
    int first_size = (*row_address) * (*column_address);
    scanf(" %d %d", row_address, column_address);
    *matrix_address = (int *)realloc(*matrix_address, (*row_address) * (*column_address) * sizeof(int));
    for (int iterator = first_size; iterator < (*row_address) * (*column_address); iterator++) {
        (*matrix_address)[iterator] = (*matrix_address)[iterator % first_size];
    }
}

void append_row(int **matrix_address, int *row_address, int *column_address)
{
    int row[*column_address];
    for (int k = 0; k < *column_address; k++) {
        scanf(" %d", &row[k]);
    }
    *matrix_address = (int *)realloc(*matrix_address, ((*row_address) + 1) * (*column_address) * sizeof(int));
    for (int j = 0; j < (*column_address); j++) {
        (*matrix_address)[(*row_address) * (*column_address) + j] = row[j];
    }
    (*row_address)++;
}

void insert_row(int *matrix, int **matrix_address, int *row_address, int *column_address)
{
    int insert;
    scanf(" %d", &insert);
    int row[*column_address];
    for (int k = 0; k < *column_address; k++) {
        scanf(" %d", &row[k]);
    }
    *matrix_address = (int *)realloc(*matrix_address, ((*row_address) + 1) * (*column_address) * sizeof(int));
    for (int i = 0; i < insert; i++) {
        for (int j = 0; j < *column_address; j++) {
            (*matrix_address)[i * (*column_address) + j] = matrix[i * (*column_address) + j];
        }
    }
    for (int k = 0; k < *column_address; k++) {
        (*matrix_address)[insert * (*column_address) + k] = row[k];
    }
    for (int i = insert + 1; i < *row_address + 1; i++) {
        for (int j = 0; j < *column_address; j++)  {
            (*matrix_address)[i * (*column_address) + j] = matrix[(i - 1) * (*column_address) + j];
        }
    }
    (*row_address)++;
}

void append_column(int *matrix, int **matrix_address, int *row_address, int *column_address)
{
    int column[*row_address];
    for (int k = 0; k < *row_address; k++) {
        scanf(" %d", &column[k]);
    }
    *matrix_address = (int *)realloc(*matrix_address, (*row_address) * ((*column_address) + 1) * sizeof(int));
    for (int i = 0; i < *row_address; i++) {
        for (int j = 0; j < *column_address; j++) {
            (*matrix_address)[i * (*column_address + 1) + j] = matrix[i * (*column_address) + j];
        }
        (*matrix_address)[i * (*column_address + 1) + (*column_address)] = column[i];
    }
    (*column_address)++;
}

void insert_column(int *matrix, int **matrix_address, int *row_address, int *column_address)
{
    int insert;
    scanf(" %d", &insert);
    int column[*row_address];
    for (int k = 0; k < *row_address; k++) {
        scanf(" %d", &column[k]);
    }
    *matrix_address = (int *)realloc(*matrix_address, (*row_address) * ((*column_address) + 1) * sizeof(int));
    for (int i = 0; i < *row_address; i++) {
        for (int j = 0; j < insert; j++) {
            (*matrix_address)[i * (*column_address + 1) + j] = matrix[i * (*column_address) + j];
        }
        (*matrix_address)[i * (*column_address + 1) + insert] = column[i];
    }
    for (int i = 0; i < *row_address; i++) {
        for (int j = insert + 1; j < *column_address + 1; j++)  {
            (*matrix_address)[i * (*column_address + 1) + j] = matrix[i * (*column_address) + j - 1];
        }
    }
    (*column_address)++;
}

void delete_row(int *matrix, int **matrix_address, int *row_address, int *column_address)
{
    int delete;
    scanf(" %d", &delete);
    for (int i = 0; i < delete; i++) {
        for (int j = 0; j < *column_address; j++) {
            (*matrix_address)[i * (*column_address) + j] = matrix[i * (*column_address) + j];
        }
    }
    for (int i = delete; i < *row_address - 1; i++) {
        for (int j = 0; j < *column_address; j++)  {
            (*matrix_address)[i * (*column_address) + j] = matrix[(i + 1) * (*column_address) + j];
        }
    }
    *matrix_address = (int *)realloc(*matrix_address, (*row_address - 1) * (*column_address) * sizeof(int));
    (*row_address)--;
}

void delete_column(int *matrix, int **matrix_address, int *row_address, int *column_address)
{
    int delete;
    scanf(" %d", &delete);
    for (int i = 0; i < *row_address; i++) {
        for (int j = 0; j < delete; j++) {
            (*matrix_address)[i * (*column_address - 1) + j] = matrix[i * (*column_address) + j];
        }
    }
    for (int i = 0; i < *row_address; i++) {
        for (int j = delete; j < *column_address - 1; j++)  {
            (*matrix_address)[i * ((*column_address) - 1) + j] = matrix[i * (*column_address) + j + 1];
        }
    }
    *matrix_address = (int *)realloc(*matrix_address, (*row_address) * (*column_address - 1) * sizeof(int));
    (*column_address)--;
}

void tile(int *matrix, int **matrix_address, int *row_address, int *column_address)
{
    int x, y;
    scanf(" %d %d", &x, &y);
    *matrix_address = (int *)realloc(*matrix_address, ((*row_address) * y) * ((*column_address) * x) * sizeof(int));
    for (int i = 0; i < (*row_address) * y; i++) {
        for (int j = 0; j < (*column_address) * x; j++) {
            (*matrix_address)[i * (*column_address * x) + j] = matrix[(i % (*row_address)) * (*column_address) +  j % (*column_address)];
        }
    }
    (*row_address) *= y;
    (*column_address) *= x;
}

void transpose(int *matrix, int **matrix_address, int *row_address, int *column_address)
{
    for (int i = 0; i < *row_address; i++) {
        for (int j = 0; j < *column_address; j++) {
            (*matrix_address)[j * (*row_address) + i] = matrix[i * (*column_address) + j];
        }
    }
    // swapping row and column
    int tmp = *row_address;
    *row_address = *column_address;
    *column_address = tmp;
}

int main()
{
    int row, column;
    scanf("%d %d", &row, &column);
    int *matrix = (int *)malloc(row * column * sizeof(int));
    for (int i = 0; i < row * column; i++) {
        scanf("%d", matrix + i);
    }

    int *copy_matrix = (int *)malloc(row * column * sizeof(int));
    for (int i = 0; i < row * column; i++) {
            copy_matrix[i] = matrix[i];
    }
    
    char instruction[20];
    while (1) {
        scanf("%s", instruction);
        //gets(instruction);
        if (!strcmp(instruction, "exit"))
            break;
        for (int i = 0; i < row * column; i++) {
            copy_matrix[i] = matrix[i];
        }
        if (!strcmp(instruction, "ravel"))
            ravel(copy_matrix, &row, &column);
        else if (!strcmp(instruction, "reshape"))
            reshape(&row, &column);
        else if (!strcmp(instruction, "resize"))
            resize(&matrix, &row, &column);
        else if (!strcmp(instruction, "append_row"))
            append_row(&matrix, &row, &column);
        else if (!strcmp(instruction, "insert_row"))
            insert_row(copy_matrix, &matrix, &row, &column);
        else if (!strcmp(instruction, "append_column"))
            append_column(copy_matrix, &matrix, &row, &column);
        else if (!strcmp(instruction, "insert_column"))
            insert_column(copy_matrix, &matrix, &row, &column);
        else if (!strcmp(instruction, "delete_row"))
            delete_row(copy_matrix, &matrix, &row, &column);   
        else if (!strcmp(instruction, "delete_column"))
            delete_column(copy_matrix, &matrix, &row, &column);
        else if (!strcmp(instruction, "tile"))
            tile(copy_matrix, &matrix, &row, &column);
        else if (!strcmp(instruction, "transpose"))
            transpose(copy_matrix, &matrix, &row, &column);
        if (strcmp(instruction, "ravel"))
            print_matrix(matrix, row, column);
    }
    
    free(matrix);
    matrix = NULL;
    free(copy_matrix);
    copy_matrix = NULL;

    return 0;
}

这是我的示例输入:

3 3
95 61 70
98 84 45
92 21 63
append_row
65 45 28
append_row
66 66 67
insert_column
2
32 40 1 52 52
delete_column
2
insert_column
0
63 98 71 49 94
insert_column
2
57 16 45 75 10
exit
c pointers matrix input segmentation-fault
2个回答
1
投票

代码太复杂:

  • 当您分别传递矩阵数组和维度时,您需要在太多地方取消引用指针,这使得代码难以理解。
  • main
    循环中,您传递
    copy_matrix
    以及可能更新的
    row
    column
    值,但
    copy_matrix
    数组永远不会重新分配,因此它可能会变得太小而无法处理
    matrix 的副本
    价值观。

您应该使用包含指向数组和维度的指针的

matrix
结构,并将指向这些结构的指针传递给各种处理程序。

这里有修改版供大家学习:

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct matrix {
    size_t rows, cols;
    int *arr;
} matrix;

#define MATRIX_GET(m, row, col)  ((m)->arr[(m)->cols * (row) + (col)])
#define MATRIX_SET(m, row, col, val)  ((m)->arr[(m)->cols * (row) + (col)] = (val))

bool matrix_allocate(matrix *m, int rows, int cols) {
    m->rows = rows;
    m->cols = cols;
    m->arr = calloc(rows * cols, sizeof(*m->arr));
    return m->arr != NULL;
}

void matrix_deallocate(matrix *m) {
    free(m->arr);
    m->arr = NULL;
}

bool matrix_copy(matrix *dest, const matrix *src) {
    matrix_deallocate(dest);
    if (!matrix_allocate(dest, src->rows, src->cols))
        return false;
    memcpy(dest->arr, src->arr, src->rows * src->cols * sizeof(*dest->arr));
    return true;
}

void print_matrix(const matrix *m) {
    for (size_t i = 0; i < m->rows; i++) {
        for (size_t j = 0; j < m->cols; j++) {
            printf("%d ", MATRIX_GET(m, i, j));
        }
        printf("\n");
    }
}

void ravel(const matrix *m) {
    for (size_t i = 0, size = m->rows * m->cols; i < size; i++) {
        printf("%d ", m->arr[i]);
    }
    printf("\n");
}

bool reshape(matrix *m)
{
    int new_rows, new_cols;
    if (scanf("%d %d", &new_rows, &new_cols) != 2)
        return false;

    size_t count = m->rows * m->cols;
    size_t new_count = new_rows * new_cols;
    int *new_arr = realloc(m->arr, sizeof(int) * new_rows * new_cols);
    if (new_arr == NULL)
        return false;
    for (size_t i = count; i < new_count; i++)
        new_arr[i] = 0;
    m->rows = new_rows;
    m->cols = new_cols;
    m->arr = new_arr;
    return true;
}

bool resize(matrix *m)
{
    int new_rows, new_cols;
    if (scanf("%d %d", &new_rows, &new_cols) != 2)
        return false;

    size_t count = m->rows * m->cols;
    size_t new_count = new_rows * new_cols;
    int *new_arr = realloc(m->arr, sizeof(int) * new_rows * new_cols);
    if (new_arr == NULL)
        return false;
    if (count == 0) {
        for (size_t i = 0; i < new_count; i++)
            new_arr[i] = 0;
    } else {
        for (size_t i = count; i < new_count; i++) {
            new_arr[i] = new_arr[i % count];
        }
    }
    m->rows = new_rows;
    m->cols = new_cols;
    m->arr = new_arr;
    return true;
}

bool insert_row_internal(matrix *m, size_t insert)
{
    int row[m->cols];
    for (size_t k = 0; k < m->cols; k++) {
        row[k] = 0;
        scanf("%d", &row[k]);
    }
    size_t new_rows = m->rows + 1;
    int *new_arr = realloc(m->arr, sizeof(*new_arr) * new_rows * m->cols);
    if (new_arr == NULL)
        return false;
    if (insert > m->rows) {
        insert = m->rows;
    } else
    if (insert < m->rows) {
        memmove(&new_arr[(insert + 1) * m->cols], &new_arr[insert * m->cols],
                sizeof(*new_arr) * (m->rows - insert) * m->cols);
    }
    memcpy(&new_arr[insert * m->cols], row, sizeof(*new_arr) * m->cols);
    m->rows = new_rows;
    m->arr = new_arr;
    return true;
}

bool append_row(matrix *m)
{
    return insert_row_internal(m, m->rows);
}

bool insert_row(matrix *m)
{
    int insert = 0;
    scanf("%d", &insert);
    return insert_row_internal(m, insert);
}

bool insert_column_internal(matrix *m, size_t insert)
{
    int column[m->rows];
    for (size_t k = 0; k < m->rows; k++) {
        column[k] = 0;
        scanf("%d", &column[k]);
    }
    size_t new_cols = m->cols + 1;
    int *new_arr = realloc(m->arr, sizeof(*new_arr) * m->rows * new_cols);
    if (new_arr == NULL)
        return false;
    if (insert > m->cols)
        insert = m->cols;
    // copy from the end to allow for insertions
    for (size_t i = m->rows; i-- > 0;) {
        for (size_t j = m->cols; j-- > insert;) {
            new_arr[new_cols * i + j + 1] = new_arr[m->cols * i + j];
        }
        new_arr[new_cols * i + insert] = column[i];
        for (size_t j = insert; j-- > 0;) {
            new_arr[new_cols * i + j] = new_arr[m->cols * i + j];
        }
    }
    m->cols = new_cols;
    m->arr = new_arr;
    return true;
}

bool append_column(matrix *m)
{
    return insert_column_internal(m, m->cols);
}

bool insert_column(matrix *m)
{
    int insert = m->cols;
    scanf("%d", &insert);
    return insert_column_internal(m, insert);
}

bool delete_row(matrix *m)
{
    int delete = m->rows;
    scanf("%d", &delete);
    if (delete < 0 || (size_t)delete >= m->rows)
        return false;
    memmove(&m->arr[delete * m->cols], &m->arr[(delete + 1) * m->cols],
            sizeof(*m->arr) * (m->rows - delete - 1) * m->cols);
    int *new_arr = realloc(m->arr, sizeof(*new_arr) * (m->rows - 1) * m->cols);
    if (new_arr != NULL)
        m->arr = new_arr;
    m->rows--;
    return true;
}

bool delete_column(matrix *m)
{
    int delete = m->cols;
    scanf(" %d", &delete);
    if (delete < 0 || (size_t)delete >= m->cols)
        return false;
    for (size_t i = 0; i < m->rows; i++) {
        for (size_t j = 0; j < (size_t)delete; j++) {
            m->arr[i * (m->cols - 1) + j] = m->arr[i * m->cols + j];
        }
        for (size_t j = delete + 1; j < m->cols - 1; j++) {
            m->arr[i * (m->cols - 1) + j - 1] = m->arr[i * m->cols + j];
        }
    }
    int *new_arr = realloc(m->arr, sizeof(*new_arr) * m->rows * (m->cols - 1));
    if (new_arr != NULL)
        m->arr = new_arr;
    m->cols--;
    return true;
}

bool tile(matrix *m)
{
    int x = 0, y = 0;
    scanf("%d %d", &x, &y);
    if (x <= 0 || y <= 0)
        return false;
    size_t rows = m->rows;
    size_t cols = m->cols;
    int *new_arr = calloc(sizeof(*new_arr), rows * cols * x * y);
    if (new_arr != NULL)
        return false;
    for (size_t i = 0; i < rows * y; i++) {
        for (size_t j = 0; j < cols * x; j++) {
            new_arr[i * (cols * x) + j] = m->arr[(i % rows) * cols + j % cols];
        }
    }
    free(m->arr);
    m->arr = new_arr;
    m->rows *= y;
    m->cols *= x;
    return true;
}

bool transpose(matrix *m)
{
    size_t rows = m->rows;
    size_t cols = m->cols;
    int *new_arr = calloc(sizeof(*new_arr), rows * cols);
    if (new_arr != NULL)
        return false;
    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            new_arr[j * rows + i] = m->arr[i * cols + j];
        }
    }
    // swapping rows and cols
    m->rows = cols;
    m->cols = rows;
    free(m->arr);
    m->arr = new_arr;
    return true;
}

int main(void)
{
    matrix m;
    int rows = 0, cols = 0;
    scanf("%d %d", &rows, &cols);

    if (!matrix_allocate(&m, rows, cols))
        return 1;
    for (size_t i = 0; i < m.rows * m.cols; i++) {
        m.arr[i] = 0;
        scanf("%d", &m.arr[i]);
    }

    char instruction[20];
    while (scanf("%19s", instruction) == 1) {
        bool success = true;
        if (!strcmp(instruction, "exit")) {
            break;
        } else
        if (!strcmp(instruction, "reshape")) {
            success = reshape(&m);
        } else
        if (!strcmp(instruction, "resize")) {
            success = resize(&m);
        } else
        if (!strcmp(instruction, "append_row")) {
            success = append_row(&m);
        } else
        if (!strcmp(instruction, "insert_row")) {
            success = insert_row(&m);
        } else
        if (!strcmp(instruction, "append_column")) {
            success = append_column(&m);
        } else
        if (!strcmp(instruction, "insert_column")) {
            success = insert_column(&m);
        } else
        if (!strcmp(instruction, "delete_row")) {
            success = delete_row(&m);
        } else
        if (!strcmp(instruction, "delete_column")) {
            success = delete_column(&m);
        } else
        if (!strcmp(instruction, "tile")) {
            success = tile(&m);
        } else
        if (!strcmp(instruction, "transpose")) {
            success = transpose(&m);
        } else
        if (!strcmp(instruction, "ravel")) {
            ravel(&m);
            continue;
        } else
        if (!strcmp(instruction, "print")) {
            print_matrix(&m);
            continue;
        } else
        if (isdigit((unsigned char)*instruction)) {
            /* ignore numbers */
            continue;
        } else {
            printf("unknown command: %s\n", instruction);
            continue;
        }
        if (!success) {
            printf("command failed!\n");
        }
        print_matrix(&m);
    }

    matrix_deallocate(&m);
    return 0;
}

0
投票
  1. main()
    中,您不会更改
    copy_matrix
    的大小,但会更改
    matrix
    的大小(
    row
    column
    )。最小的修复方法是在
    while(1)
    循环中重新创建矩阵。

     while (1) {
         scanf("%19s", instruction);
         if (!strcmp(instruction, "exit"))
             break;
         int* copy_matrix = malloc(row * column * sizeof *copy_matrix);
         if(!copy_matrix)
             exit(1);
         // ...
         free(copy_matrix);
         copy_matrix = NULL;
     }
    

    对我来说,这是改变

    matrix
    形状的函数的内部实现细节,因此我建议您删除该参数并在每个需要它的函数中进行内部处理。

  2. 考虑使用

    memcpy()

  3. 使用

    scanf()
    读取字符串时始终使用最大字段宽度,以避免缓冲区溢出。

  4. (不固定)始终检查 I/O 操作的返回值,如

    scanf()
    ,否则您可能正在操作未初始化的变量。

  5. (未修复)

    foo = relloc(foo, ...)
    失败时会泄漏内存。在覆盖
    foo
    之前,您需要进行 NULL 检查,因此即使它与策略类似
    exit(1)
    ,也请使用临时值。这会安抚
    gcc -fanalyzer

$ ./a.out < input.txt
95 61 70 
98 84 45 
92 21 63 
65 45 28 
95 61 70 
98 84 45 
92 21 63 
65 45 28 
66 66 67 
95 61 32 70 
98 84 40 45 
92 21 1 63 
65 45 52 28 
66 66 52 67 
95 61 70 
98 84 45 
92 21 63 
65 45 28 
66 66 67 
63 95 61 70 
98 98 84 45 
71 92 21 63 
49 65 45 28 
94 66 66 67 
63 95 57 61 70 
98 98 16 84 45 
71 92 45 21 63 
49 65 75 45 28 
94 66 10 66 67 
© www.soinside.com 2019 - 2024. All rights reserved.