#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. кстати, спасибо за объяснение! Я даже не знал, что это работает таким образом.