Как вернуться к основной функции из функции void zmianaWierszy (…)?

#c #string

#c #строка

Вопрос:

Мой код не возвращается из функции zamianaWierszy , приведенной ниже:

 #include"stdio.h"
#include"string.h"
#include"stdlib.h"

void zamianaWierszy(int pierwszy, int drugi,char*tabstat[]) {
    char*pamietajPierwszy;

    size_t rozmiarTab = strlen(*tabstat);
    pamietajPierwszy = tabstat[pierwszy - 1];
    tabstat[pierwszy - 1] = tabstat[drugi - 1];
    tabstat[drugi - 1] = pamietajPierwszy;

    for (int i = 0; i < rozmiarTab; i  ) {
        puts(tabstat[i]);
    }
}

int main()
{
    int pierwszy, drugi, pusty;

    char *tabstat[] = {
        (char*)"abcde",
        (char*)"fghi",
        (char*)"jklmn",
        (char*)"koder"
    };
    printf("Podaj wybrane wiersze,które chcesz przestawić:");
    scanf("%d %d", amp;pierwszy, amp;drugi);
    zamianaWierszy(pierwszy, drugi, tabstat);

    printf("Podaj po którym wierszu chcesz wstawić pusty wiersz:");
    scanf("%d", amp;pusty);
    pustyWiersz(pusty, tabstat);
    return 0;
}    
  

Я не вижу выходных данных printf("Podaj po którym wierszu chcesz wstawić pusty wiersz:") в main.

Комментарии:

1. Может быть, это только мне кажется, но мне кажется, что было бы легче следовать вашему коду и понимать назначение, если вы переведете его на общий язык. Мне было трудно даже найти, где printf("Podaj po którym wierszu chcesz wstawić pusty wiersz:") находится.

2. #include <iostream> это C.

3. Что вы подразумеваете под «затем вернитесь к main для печати ..» ? Функция zamianaWierszy() , выполнив управление, возвращается к вызывающей функции, которая main() в вашем случае. В вашей функции есть какая-то проблема zamianaWierszy() , например, for цикл повторяется rozmiarTab раз, что соответствует длине строки, на которую указывает первый указатель в char массиве указателей tabstat . Вместо этого вы должны использовать количество строк, указатели на которые tabstat указывают. Пожалуйста, четко укажите проблему, с которой вы столкнулись.

4. Моя программа показывает только результат функции ‘zamianaWierszy()’ и дальше не идет. Я думаю, что функция ‘Zmianawierszy()’ работает должным образом, но программа останавливается после рекурсии ZmianaWierszy()’ в main.

5. Камиль: Да, это C, но я включил ‘system («пауза»)’, и мне это было нужно. Мешает ли это правильному запуску программы?

Ответ №1:

В вашем коде много неправильных элементов, основные из которых:

  • Проверьте результат scanf или, возможно, у вас есть инициализированные значения для pierwszy и drugi
  • Если pierwszy равно 0 или отрицательно, это приведет к перезаписи фрейма стека вызывающей функции: tabstat[pierwszy - 1] = ...
  • Если drugi равно 0 или отрицательно, это приведет к перезаписи фрейма стека вызывающей функции: tabstat[drugi - 1] = ...
  • rozmiarTab будет содержать размер первой строки (5) вместо количества строк в tabstat , как это предполагается. Итак, ваш цикл for собирается получить доступ к дополнительному элементу вне диапазона. Однако это, вероятно, приведет к печати какого-либо мусора или сбою, но вряд ли повлияет на обратный адрес вашей функции.

При перезаписи фрейма стека вызывающего объекта вы, скорее всего, перезапишете адрес возврата вашей функции, и никто не знает, куда может вернуться ваша функция … 🙂

Итак, вам нужно проверить возвращаемое значение scanf и значения pierwszy и drugi и исправить значение rozmiarTab .

Комментарии:

1. Да, я сделал это, потому что предполагал, что пользователь выдаст pierwszy, други>0 🙂

2. Да 😉 Именно так, как я хотел, но дальше это не идет, и возникает проблема.

3. Я нашел! Я должен был указать i< rozmiarTab-1 , потому что я вышел из массива.

4. И вот оно, но я не знаю, как вставить пустой стих в массив в C. Я попробую что-нибудь с функцией malloc . Хорошая ли это сделка? Извините, что беспокою вас, но я новичок, и я действительно хочу научиться программировать. Заранее спасибо за ваше внимание 🙂

5. Я не понял этого: «как вставить пустой стих в массив в C». Вы имеете в виду, что хотите добавить больше строк в этот tabstat массив, например?

Ответ №2:

Ваша программа имеет неопределенное поведение, потому что она обращается к массиву, tabstat превышающему его размер в функции zamianaWierszy() . Неопределенное поведение включает в себя, что оно может выполняться неправильно (либо сбой, либо молчаливая генерация неверных результатов), или оно может случайно выполнять именно то, что задумал программист.

Посмотрите на это утверждение zamianaWierszy() :

 size_t rozmiarTab = strlen(*tabstat);
  

*tabstat Это указатель на первую строку массива, tabstat которая является строковым литералом "abcde" . strlen() Вернет 5 (размер строки без включения завершающего нулевого символа). for Цикл повторяется 5 раз ( 0 по 4 -му индексу):

 for (int i = 0; i < rozmiarTab; i  ) {
    puts(tabstat[i]);    // <===========
}
  

Здесь for цикл завершает доступ tabstat[4] , и допустимый индекс массива tabstat равен от 0 до 3 ( 4 элементов). В C вы должны быть очень осторожны при использовании массива в вашей программе и следить за тем, чтобы не обращаться к массиву, превышающему его размер.

Если вы хотите выполнить итерацию ко всем элементам tabstat функции zamianaWierszy() , вы должны передать ее размер в качестве аргумента, потому что когда вы передаете массив функции, он распадается на указатель.

Вы должны сделать:

 void zamianaWierszy(int pierwszy, int drugi, char*tabstat[], size_t tabstat_sz); //declaration

// From the main(), you should call zamianaWierszy() like this
int main() {
    int pierwszy, drugi;

    char *tabstat[] = {
               "abcde",
               "fghi",
               "jklmn",
               "koder"
    };
    ......
    ......
    scanf("%d %d", amp;pierwszy, amp;drugi);
    // Make sure to validate the input from user
    ......
    ......
    zamianaWierszy(pierwszy, drugi, tabstat, sizeof(tabstat)/sizeof(tabstat[0]));
    ......
    ......
}

void zamianaWierszy(int pierwszy, int drugi, char*tabstat[], size_t tabstat_sz) {
    char*pamietajPierwszy;

    size_t rozmiarTab = tabstat_sz;   // No need of rozmiarTab variable, you can directly use tabstat_sz
    pamietajPierwszy = tabstat[pierwszy - 1];
    tabstat[pierwszy - 1] = tabstat[drugi - 1];
    tabstat[drugi - 1] = pamietajPierwszy;

    for (int i = 0; i < rozmiarTab; i  ) {
        puts(tabstat[i]);
    }
}
  

Кроме того, вы должны проверить scanf() возврат и должны подтвердить введенные пользователем данные перед их использованием. Подобные случаи — что, если пользователь ввел данные как 100 и 200 для pierwszy и drugi . Их использование приведет к неопределенному поведению, поскольку размер tabstat равен 4 .

Комментарии:

1. Ты гений! Деление sizeof(tabstat) на sizeof(tabstat[0] защищает программу от переполнения? Не могли бы вы объяснить, почему мы должны сделать это таким образом?

2. Ранее я просто проверял, сколько стоит rozmiarTab, и выводил 5, но у меня, как вы упомянули, 4 элемента, поэтому я просто меняю это: i<rozmiarTab-1 в цикле. И это тоже работало 😉 Большое спасибо за вашу помощь! <3

3. @KasiaIks sizeof(tabstat)/sizeof(tabstat[0]) сообщит вам размер tabstat массива. Если вы добавите еще несколько элементов в tabstat массив, вам не нужно беспокоиться о его размере, так как sizeof(tabstat)/sizeof(tabstat[0]) размер будет вычисляться на основе количества элементов в массиве в то время. Если вы все еще используете size_t rozmiarTab = strlen(*tabstat); , просто попробуйте заменить «abcde» на «abcdefghijklmnopqrst» и проверьте, работает ли ваша программа нормально или нет. strlen(*tabstat) выдаст длину строкового литерала, на который указывает первый указатель из tabstat массива указателей char.

4. Ооо, я думал, что sizeof (tabstat) будет достаточным, и я был так удивлен, почему мой массив равен 5, когда у меня всего 4 элемента. Что это учитывало дополнительно?

5. кстати, спасибо за объяснение! Я даже не знал, что это работает таким образом.