Problem z programem insert w C

0

Witam. Mam problem z programem. Nie działa jak należy. Na wyniku podaje 'diction', czyli traci ogon z 1. członu. Na tę chwilę nie wiem, co jest nie tak. Jakieś porady? (Program ma też działać dla większej niż 2 wywołań funkcji) Dziękuję z góry :)

#include <stdio.h>
#include <stdlib.h>
char *insert(char *string, int place, const char *napis){
    static int check = 1;
    char *tmp;
    int i = 0, j, k1, k2;
    if(check == 1){
        while(napis[i]){
            i++;} //zlicza dl. napisu
        string = malloc(i * sizeof(*string));
        for(j = 0;j < i;j++){
            string[j] = napis[j];} //przypisuje napis do naszej zmiennej
        check++; //raport wykonania funkcji
        return string;
    }else{
        i = 0;
        k2 = place;
        while(napis[i]){
            i++;} //zliczenie dl NOWEGO napisu
        tmp = malloc(i * sizeof(char));
        while(string[j]){
            tmp[j] = string[j]; //zapamietanie starego napisu
            j++;}
        string = realloc(string, 2 * i * sizeof(*string));
        for(j = 0;j < i;j++){
            string[place] = napis[j];//dopisanie nowego napisu
            place++;}
        k1 = i + place + 1;
        while(tmp[k2]){
            string[k1] = tmp[k2]; //dopisanie straconego ogona do napisu
            k1++;
            k2++;}
        return string;
    }
}

int main(){
    char *string = calloc(1, 1);
    string = insert(string, 0, "diary");
    string = insert(string, 2, "ction");
    printf("%s\n", string);
    free(string);
    return 0;
}

0

Nie zamieszczaj png tylko kod, i najlepiej przed wklejeniem go sformatuj http://format.krzaq.cc/

1
char* insert(char* string, int place, const char* napis)
{
    int firLen = strlen(string);
    int secLen = strlen(napis);
    
    string = (char*)realloc(string, sizeof(char) * (firLen+secLen)+1);
    
    if (string == NULL) {
        return NULL;
    }

    for (int i=0; i<firLen; i++) {
        string[place+i+secLen] = string[place+i];
    }
    
    for (int i=0; i<secLen; i++) {
        string[place+i] = napis[i];
    }
    
    return string;
}
0
daniel1302 napisał(a):
char* insert(char* string, int place, const char* napis)
{
    int firLen = strlen(string);
    int secLen = strlen(napis);
    
    string = (char*)realloc(string, sizeof(char) * (firLen+secLen)+1);
        
    for (int i=0; i<firLen; i++) {
        string[place+i+secLen] = string[place+i];
    }
    
    for (int i=0; i<secLen; i++) {
        string[place+i] = napis[i];
    }
    
    return string;
}

Super :) a dałoby rade go jakos zmodyfikować, żeby działał dla 3 łańcuchów lub więcej?

0

@daniel1302:
1: nie zadziała to gdy zaczniemy od zupełnie pustego napisu (napisem-celem będzie NULL):

int main(){
    char *string = NULL;
    string = insert(string, 0, "diary");
    printf("%s\n", string);
    free(string);
    return 0;
}

2: bardziej poprawne byłoby napisać:
string = (char*)realloc(string, sizeof(char) * (firLen+secLen+1));
zamiast
string = (char*)realloc(string, sizeof(char) * (firLen+secLen)+1);
W końcu \0 w łańcuchach znakowych jest… znakiem. Dasz sobie rękę uciąć, że wszystkie kompilatory i na wszystkich architekturach obecnych i przyszłych char będzie mieć 1 bajt?

0

@daniel1302: Pierwsza pętla przeniesie za dużo znaków i w niewłaściwej kolejności.
Sprawdź dla:

int main(){
    char *string = calloc(1, 1);
    string = insert(string, 0, "diary");
    printf("%s\n", string);
    string = insert(string, 2, "ction");
    printf("%s\n", string);
    string = insert(string, 7, " v");
    printf("%s\n", string);
    free(string);
    return 0;
}
0

Tak, bo realloc nie gwarantuje, że w przypadku rozszerzania bloku pamięci dołożą się komórki wyłącznie za poprzednio zaalokowanym blokiem. W takim przypadku realloc może zwrócić nowy adres pamięci. A zatem trzeba kopiowanie przeprowadzić w 3 krokach (3 forach). Nie można iść tak na łatwiznę :)

0

A masz gdzieś wymagane żeby użyć realloc? A gdyby użyć poczciwego malloc i free

char* insert(char* string, int place, const char* napis) {
    int i;
    int sLen = strlen(string);
    int nLen = strlen(napis);

    char* tmp = (char*)malloc(sizeof(char) * (sLen + nLen + 1));

    for(i = 0; i < place; i++) {
        tmp[i] = string[i];
    }
    for(int j = 0; j < nLen; j++, i++) {
        tmp[i] = napis[j];
    }
    for(int j = place; j < sLen; j++, i++) {
        tmp[i] = string[j];
    }
    tmp[i] = '\0';

    free(string);

    return tmp;
}

Skoro jak piszesz ten char *string = calloc(1,1) jest ustalony z góry to już nie sprawdzam, że jest NULL. Innych rzeczy też nie sprawdzam (np. czy place jest liczbą z zakresu [0, sLen-1]). Jeśli potrzebujesz tego to są już to proste warunki.

2

Tutaj masz działającą funkcję, tym razem z realloc'kiem:

char* insert(char* string, int place, const char* napis) {
    int sLen = strlen(string);
    int nLen = strlen(napis);

    string = (char*)realloc(string, sizeof(char) * (sLen + nLen + 1));

    for(int i = 0; i < sLen - place; i++) {
        string[sLen + nLen - i - 1] = string[sLen - i - 1];
    }
    for(int i = place, j = 0; j < nLen; i++, j++) {
        string[i] = napis[j];
    }
    string[sLen + nLen] = '\0';

    return string;
}

Wiersz 13 można włożyć do pierwszego fora ale moim zdaniem kod jest czytelniejszy. Zrobisz jak uważasz.

0
// zamiast memcpy
void charcopyn(const char *src, char *dst, int count)
{
    while(count--) *dst++ = *src++;
}

char* insert(char* string, int place, const char* napis) {
    int sLen = strlen(string);
    int nLen = strlen(napis);

    // walidacja wejścia
    if (nLen == 0) return string;
    if (place<0) place = 0;
    if (place>sLen) place=sLen;

    string = realloc(string, sizeof(char) * (sLen + nLen + 1));
    charcopyn(string + place, string + place + nLen, sLen - place + 1); // zrób miejsce na napis w string
    charcopyn(napis, string + place, sLen); // wstaw napis

    return string;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1