3

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?

Elgin Cahangirov
  • 1,932
  • 4
  • 24
  • 45

2 Answers2

3

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);
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • Re “You are not allowed to modify string literals”: Proper phrasing is that the C standard does not define what happens when you attempt to modify string literals. The C standard does not actually prohibit trying; you are allowed to modify them, or at least to try. This distinction does not make a big difference here, but it is important to understanding the C standard in general: The C standard provides an open area where you can use defined features and also bring in your own; it is not a walled garden that you are barred from leaving. – Eric Postpischil Oct 03 '20 at 13:36
  • 1
    Ok, but using `memcpy` to copy the value of a pointer to char into another pointer to char is a bit odd. – Bob__ Oct 03 '20 at 14:00
3

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);
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189