|
Программирование >> Перегруженные имена функций и идентификаторы
f3(array2, nrows, ncolumns); Следующие два вызова, возможно, будут работать, но они включают сомнительные приведения типов, и работают лишь в том случае, когда динамически задаваемое число столбцов ncolumns совпадает с NCOLUMS: f1((int (*)[NCOLUMNS])(*array2), nrows, ncolumns); f1((int (*)[NCOLUMNS])array3, nrows, ncolumns); Необходимо еще раз отметить, что передача &array[0][0] функции f2 не совсем соответствует стандарту. Если вы способны понять, почему все вышеперечисленные вызовы работают и написаны именно так, а не иначе, и если вы понимаете, почему сочетания, не попавшие в список, работать не будут, то у вас очень хорошее понимание массивов и указателей (и нескольких других областей) Си. Вот изящный трюк: если я пишу int realarray[10]; int *array = &realarray[-1];, то теперь можно рассматривать array как массив, у которого индекс первого элемента равен единице Хотя этот прием внешне привлекателен, он не удовлетворяет стандартам Си. Арифметические действия над указателями определены лишь тогда, когда указатель ссылается на выделенный блок памяти или на воображаемый завершающий элемент, следующий сразу за блоком. В противном случае поведение программы не определено, даже если указатель не переназначается. Код, приведенный выше, плох тем, что при уменьшении смещения может быть получен неверный адрес (возможно, из-за циклического перехода адреса при пересечении границы сегмента). У меня определен указатель на char, который указывает еще и на int, причем мне необходимо переходить к следующему элементу типа int. Почему ((int *)p)++; не работает? В языке Си оператор преобразования типа не означает будем действовать так, как будто эти биты имеют другой тип ; это оператор, который действительно выполняет преобразования, причем по определению получается значение типа rvalue, которому нельзя присвоить новое значение и к которому не применим оператор ++. (Следует считать аномалией то, что компиляторы pcc и расширения gcc вообще воспринимают выражения приведенного выше типа.) Скажите то, что думаете: p = (char *)((int *)p + 1); или просто p += sizeof(int); Могу я использовать void **, чтобы передать функции по ссылке обобщенный указатель? Стандартного решения не существует, поскольку в Си нет общего типа указатель-на-указатель. void * выступает в роли обобщенного указателя только потому, что автоматически осуществляются преобразования в ту и другую сторону, когда встречаются разные типы указателей. Эти преобразования не могут быть выполнены (истинный тип указателя неизвестен), если осуществляется попытка косвенной адресации, когда void ** указывает на что-то отличное от void *. Почему не работает фрагмент кода: char *answer; printf( Type something:\n ); gets(answer); printf( You typed \ %s\ \n , answer); Указатель answer , который передается функции gets как место, в котором должны храниться вводимые символы, не инициализирован, т.е. не указывает на какое-то выделенное место. Иными словами, нельзя сказать, на что указывает answer . (Так как локальные переменные не инициализируются, они вначале обычно содержат мусор , то есть даже не гарантируется, что в начале answer - это нулевой указатель. Простейший способ исправить программу - использовать локальный массив вместо указателя, предоставив компилятору заботу о выделении памяти: #include <string.h> char answer[100], *p; printf( Type something:\n ); fgets(answer, sizeof(answer), stdin); if((p = strchr(answer, \n)) != NULL) *p = \0; printf( You typed \ %s\ \n , answer); Заметьте, что в этом примере используется fgets() вместо gets(), что позволяет указать размер массива, так что выход за пределы массива, когда пользователь введет слишком длинную строку, становится невозможным. (К сожалению, fgets() не удаляет автоматически завершающий символ конца строки \n, как это делает gets()). Для выделения памяти можно также использовать malloc(). Не могу заставить работать strcat. В моей программе char *s1 = Hello, ; char *s2 = world! ; char *s3 = strcat(s1, s2); но результаты весьма странные Проблема снова состоит в том, что не выделено место для результата объединения. Си не поддерживает автоматически переменные типа string. Компиляторы Си выделяют память только под объекты, явно указанные в исходном тексте (в случае стрингов это может быть массив литер или символы, заключенные в двойные кавычки). Программист должен сам позаботиться о том, чтобы была выделена память для результата, который получается в процессе выполнения программы, например результата объединения строк. Обычно это достигается объявлением массива или вызовом malloc. Функция strcat не выделяет память; вторая строка присоединяется к первой. Следовательно, одно из исправлений - в задании первой строки в виде массива достаточной длины: char s1[20] = Hello, ; Так как strcat возвращает указатель на первую строку (в нашем случае s1), переменная s3 - лишняя. В справочнике о функции strcat сказано, что она использует в качестве аргументов два указателя на char. Откуда мне знать о выделении памяти? Как правило, при использовании указателей всегда необходимо иметь в виду выделение памяти, по крайней мере, быть уверенным, что компилятор делает это для вас. Если в документации на библиотечную функцию явно ничего не сказано о выделении памяти, то обычно это проблема вызывающей функции. Краткое описание функции в верхней части страницы справочника в стие UNIX может ввести в заблуждение. Приведенные там фрагменты кода ближе к определению, необходимому для разработчика функции, чем для того, кто будет
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |