Lỗi Segmentation fault khi sử dụng strcpy

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

int soSanh(char const *str1, char const *str2);
void sapXep(char *ten[], int soLuongTen);
void swap(char *str1, char *str2);


int main(){
    char *str[] = {"viet", "Anh", "viet"};

    // Sap xep theo alphabet
    sapXep(str, 3);

    // Hien thi ket qua 3 string sau khi sap xep theo alphabet
    for(int i = 0; i < 3; i++){
        printf("%s\n", str[i]);
    }
    
    return 0;
}

int soSanh(char const *str1, char const *str2){
    int compareResult = strcmp(str1, str2);
    if(compareResult < 0){
        return -1;
    }
    else if(compareResult == 0){
        return 0;
    }
    else
    {
        return 1;
    }
    
}

void sapXep(char *ten[], int soLuongTen){
    for(int i = 0; i < soLuongTen - 1; i++){
        for(int j = i; j < soLuongTen; j++){
            int ketQuaSoSanh = soSanh(ten[i], ten[j]);
            if(ketQuaSoSanh > 0){
                swap(ten[i], ten[j]); 
            }
        }
    }
}

void swap(char *str1, char *str2){
    char *temp = (char *)malloc((strlen(str1)+1)*sizeof(char));
    if (temp != NULL)
    {   
        strcpy(temp, str1);
        strcpy(str1, str2);// Error!!! Segmentation fault
        strcpy(str2, temp);
    }
    free(temp);
}

Em có đề bài về việc sắp xếp mảng string c-type theo chiều tăng dần, nhưng khi chạy thử thì em gặp phải lỗi segmentation fault. Qua việc debug thì em đã phát hiện được có vẻ lỗi nó nằm ở hàm strcpy() ở trong function swap. Nhưng em không hiểu lý do sao nó lại lỗi như vậy.
Bác nào biết chỉ cho em chỗ sai với ạ.

em khai báo như vậy thì str là mảng chứa con trỏ trỏ tới chuỗi literal. Chuỗi literal thì ko thay đổi được, ví dụ em ko thể thay đổi ký tự đầu tiên của chuỗi literal “Hello” được. Hơi lạ thì em cứ nghĩ chuỗi literal như số literal là số 1 2 3 ấy, ko thể gán giá trị 2 cho số 1 được.

sửa khai báo lại là

char str[][10] = {"viet", "Anh", "viet"};

số 10 là chọn 1 số bất kì >= 5 để chứa đủ 4 ký tự “viet” và 1 ký tự null. Lúc này str là mảng có 3 phần tử, mỗi phần tử có kiểu là mảng chứa 10 ký tự (char[10])

lúc này trong hàm sắp xếp cũng phải sửa lại kiểu của tham số ten thành:

void sapXep(char (*ten)[10], int soLuongTen);

ten sẽ là con trỏ trỏ tới mảng chứa 10 ký tự. Nếu viết char *ten[10] thì thực ra nó là mảng chứa 10 con trỏ :V Bởi vậy anh thích viết dấu hoa thị * kèm sát char*: char* ten[10] cho tránh hiểu nhầm ten là con trỏ tới mảng chứa 10 ký tự :V

5 Likes

Sắp xếp thì đâu cần đến deep copy :smiley: swap con trỏ được rồi.

2 Likes

Anh ơi cách này thì giải quyết được vấn đề anh ạ.
Nhưng lại nảy sinh, giả sử chuỗi đầu vào dài hơn lượng ký tự mình khai báo, thì cách khai báo cứng str[][10] có vẻ không ổn. Mình không biết cái tên dài nhất có thể có bao nhiêu ký tự thì xử lý làm sao đây ạ?
đó cũng là vấn đề em băn khoăn khi làm bài này, vì em đã từng sử dụng khai báo số lợng ký tự tĩnh như vậy ạ.

Anh ơi em từng thử swap con trỏ, nhưng trong ngôn ngữ C, cụ thể là C-type string thì việc swap con trỏ ko swap đc C-type string.
Anh có thể đọc thử bài viết này: https://www.geeksforgeeks.org/swap-strings-in-c/

Có hai trường hợp mà :smiley:
Nếu mảng có kiểu char*[] thì swap con trỏ mới ổn, vì trong mảng có thể chứa literal.
Ngược lại, nếu mảng có kiểu char[][M] thì deep copy mới đúng.

5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?