Я новичок в C, и моя программа показалась мне очень странной:
Вот код:
#include <stdbool.h>
#include <string.h>
#include <conio.h>
#include <stdio.h>
char * p(char arg[] , char sym[] , int i , bool rv) {
char head[i],w[i];
strncpy(head,arg,i); head[i] = "\0";
int l;
for (l = 0 ; l <= (int)(strlen(sym) / i) ; l++) {
strncpy(w,sym+l*i,i); w[i] = "\0";
if (strcmp(head,w) == 0) {
if (rv) { return head; } else {
char v[strlen(arg) - i];
strcpy(v,arg+i);
v[strlen(arg)-i] = "\0";
return v;
};
};
};
return arg;
}
int main() {
printf(p("/parameter","+-\/",1,false));
getch();
}
Проблема ГЛАВНЫЙ заключается в том, что возвращаемое значение функции - это либо «строка» случайно сгенерированных кодов, либо просто ничего.
Ожидалось, что он вернет / для return h; и parameter для return v;.
Другая проблема заключается в том, что при компиляции программы НЕ обнаруживается ошибок, но появляется множество предупреждений о том, что function returns address of local variable и assignment makes integer from pointer without a cast.
С другой стороны, return arg; очень мирный и не выдает ошибок. (Попробуйте изменить мои коды в p("/parameter","+-\/",1,false), если не верите.) Что я сделал не так?
Использование функции:
p("argument_passed_to_check","symbols_accepted to_be_at_the_front","separate_for_each_
i_characters","return_header_instead_of_parameter")
ожидаемый результат:
p("-argue","/\\-",1,false) возвращает argue
p("/help","me",1,false) возвращает /help
p("/help","me",1,true) возвращает (null)
p("--parameter","--++",2,false) возвращает parameter
p("--parameter","--++",2,true) возвращает --
Резюме того, в чем я прошу помощи:
За исключением return arg, другие возвращаемые части выглядят странно: return head; выдает случайные символы; return v; вообще ничего не возвращает. Как я могу позволить им работать в соответствии с ожидаемыми результатами?
Почему есть эти предупреждения?
h и v - локальные переменные. Их не существует, когда функция возвращает значение, поэтому не возвращайте их.
Считайте предупреждения ошибками. Заменить "\ 0" на '\ 0'
Спасибо, но могу ли я спросить @MarkTolonen, означает ли это, что я должен сделать h и v глобальными для решения проблемы?
Лай Янь Хуэй, просмотрите плохой код head[i] = "\0";. Этот код пытается назначить указатель на char.
Учитывая определение char head[i], как вы думаете, где head[i] = ...; `помещает назначенные данные?
@chux Спасибо, но manoliar сказал об этом.
@AndrewHenle Извините, я не понимаю, что вы имеете в виду ... Я новичок в этом, извините.
Сколько элементов в head[]? Какой индекс у первого?
int i символов (элементов) ; индекс первого из них равен 0.
@StoryTeller: Не следует рассматривать именованные объекты как самодокументирующиеся. Имена не могут, не будучи чрезмерно длинными, содержать предварительные условия, постусловия или другую важную информацию, особенно если условия включают отношения с другими элементами. Нет ничего плохого в простых именах объектов, используемых простым знакомым образом, сопровождаемых пояснительными примечаниями и условиями, например, x < y или p указывает на символы n, оканчивающиеся нулем. Не лучше функция, наполненная многочисленными повторами PointerToNCharactersTerminatedByANull[i] = PointerToNCharacterTerminatedByANull[j];.
@EricPostpischil - Ваш встречный пример экстраполирует мой комментарий намного дальше, чем я предполагал. Я подозреваю, что это сделано намеренно, чтобы доказать свою точку зрения, но следует отметить, что я нигде не рекомендовал кодифицировать OP в названиях хорошо известных идиом (например, что такое строка в C). Я рекомендую, чтобы имя кодировало цель, которую оно служит для выполнения задачи функции, если короткое имя достаточно, фантастика. Однако в случае OP их выбор из одного имени персонажа не подходит. Как видно по серьезному пагубному влиянию удаления комментария на ясность их опубликованного кода.





Поскольку head определяется как char head[i], его последним элементом является head[i-1]. Попытка получить доступ к head[i] имеет поведение, не определенное стандартом C.
Поскольку w определяется как char w[i], его последним элементом является w[i-1]. Попытка получить доступ к w[i] имеет поведение, не определенное стандартом C.
Поскольку v определяется как char v[strlen(arg) - i], его последним элементом является v[strlen(arg) - i - 1]. Попытка получить доступ к v[strlen(arg) - 1] имеет поведение, не определенное стандартом C.
Поскольку w определен внутри заключенного в фигурные скобки блока операторов без extern или static, у него есть автоматическая продолжительность хранения, связанная с блоком, поэтому он существует только пока функция является блочной. Когда выполняется оператор return, w перестает существовать (в абстрактной машине Си). Оператор return w; пытается вернуть указатель на первый элемент w (потому что в этом случае массив автоматически преобразуется в указатель на свой первый элемент). Когда этот оператор return выполняется, указатель становится недействительным.
Поскольку v определен внутри заключенного в фигурные скобки блока операторов без extern или static, у него есть автоматическая продолжительность хранения, связанная с блоком, поэтому v существует только во время выполнения оператора. Когда выполняется return v;, выполнение блока заканчивается, и возвращенный указатель становится недействительным.
head[i] - это символ, а "\0" - это строка, содержащая один символ, поэтому head[i] = "\0"; - неправильное присвоение. Строка будет преобразована в указатель на ее первый элемент, что приведет к попытке назначить указатель на char. Это нарушение ограничения, и ваш компилятор должен выдать предупреждение об этом. Та же проблема возникает в w[i] = "\0"; и v[strlen(arg)-i] = "\0";. Правильный код будет head[i] = '\0'; (если размер head фиксирован для включения элемента head[i]).
Средства правовой защиты включают:
malloc), либо создайте строки внутри массивов, предоставленных вызывающей стороной, либо используйте массивы со статической продолжительностью хранения. Если вы используете первый вариант, динамически создаваемые массивы, вы должны предусмотреть освобождение пространства (например, когда вызывающий объект передаст их free, когда они будут выполнены). Вам следует избегать использования массивов со статической продолжительностью хранения, поскольку они имеют ограниченное и проблемное использование (например, тот факт, что для каждого определения существует только один такой массив, но функция может вызываться несколько раз вызывающими, каждый из которых хочет свои собственные отдельные данные) .Спасибо за руководство ~ (^ u ^)
Но я хотел бы спросить, почему char head[i] может возвращать случайные символы?
@LaiYanHui: Когда вы объявляете char head[i], компилятор C выделяет i байта памяти, которая будет использоваться для head. В таком случае вы обязаны использовать только эти байты i. Когда вы пытаетесь использовать head[i], который находится вне массива, компилятор вас не останавливает. Часто это приводит к тому, что ваша программа обращается к памяти за пределами массива, отведенного для head, и это может нарушить работу вашей программы различными способами. Иногда могут возникнуть другие результаты, так как оптимизация компилятором может неожиданно преобразовать вашу программу, и любое поведение, не определенное стандартом, может иметь какой-либо результат.
Большое спасибо ~
Не по теме: знаете ли вы, что может быть лучше комментария, описывающего назначение этих коротких непрозрачных имен переменных? Назначение этим переменным более длинных имен описательный, что делает комментарий ненужным.