Elgin Cahangirov
Elgin Cahangirov

Reputation: 2022

C memcpy to swap rows of 2D array

I am trying to use memcpy C library function to swap rows of 2D array(array of strings). Source files for this task is below:

main.c

#include <stdlib.h>
#include "main.h"

char *table[NBLOCK] = {
    "abcdefghi",
    "defghiabc",
    "ghiabcdef",
    "bcaefdhig",
    "efdhigbca",
    "higbcaefd",
    "cabfdeigh",
    "fdeighcab",
    "ighcabfde",
};

int main() {
    swap_rows(table, 0, 2);
    return 0;
}

main.h

#define NBLOCK 9
#define BLOCK_CELLS 9

void swap_rows(char**, int, int);

shuffle.c

#include <string.h>
#include "main.h"

void swap_rows(char **table, int r1, int r2) {
    char tmp[BLOCK_CELLS];
    size_t size = sizeof(char) * BLOCK_CELLS;

    memcpy(tmp, table[r1], size);
    memcpy(table[r1], table[r2], size); /* SIGSEGV here */
    memcpy(table[r2], tmp, size);
}

Segmentation fault occurs inside swap_rows function. Out of three memcpy calls shown above, the first one works as expected. I commented out the last two memcpy calls and added below line:

table[0][0] = 'z';

But, segmentation fault occurred again. Why I am not allowed to override values of table in swap_rows function?

Upvotes: 3

Views: 313

Answers (2)

chqrlie
chqrlie

Reputation: 144951

In your code table is not defined as a 2D array of char, it is an array of pointers to char initialized with pointers to string literals, which must not be modified.

You get a segmentation fault because the string literals are stored in read-only memory protected by the operating system.

You should either swap the pointers in swap_rows or define table as a real 2D array and swap the rows with an appropriate prototype:

#include <stdlib.h>

//#include "main.h"
#define NBLOCK 9
#define BLOCK_CELLS 9

void swap_rows(char table[][BLOCK_CELLS], int, int);

char table[NBLOCK][BLOCK_CELLS] = {
    "abcdefghi",
    "defghiabc",
    "ghiabcdef",
    "bcaefdhig",
    "efdhigbca",
    "higbcaefd",
    "cabfdeigh",
    "fdeighcab",
    "ighcabfde",
};

int main() {
    swap_rows(table, 0, 2);
    return 0;
}

void swap_rows(char table[][BLOCK_CELLS], int r1, int r2) {
    char tmp[BLOCK_CELLS];
    size_t size = sizeof(tmp);

    memcpy(tmp, table[r1], size);
    memcpy(table[r1], table[r2], size);
    memcpy(table[r2], tmp, size);
}

Upvotes: 3

MikeCAT
MikeCAT

Reputation: 75062

You are not allowed to modify string literals. For more information, see c - Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?.

You can modify values of pointers to swap rows.

void swap_rows(char **table, int r1, int r2) {
    char* tmp;

    tmp = table[r1];
    table[r1] = table[r2];
    table[r2] = tmp;
}

If you prefer to use memcpy():

void swap_rows(char **table, int r1, int r2) {
    char* tmp;
    size_t size = sizeof(tmp);

    memcpy(&tmp, &table[r1], size);
    memcpy(&table[r1], &table[r2], size);
    memcpy(&table[r2], &tmp, size);
}

Upvotes: 3

Related Questions