Приведение int к указателю в С

Модератор: Модераторы разделов

Ответить
Аватара пользователя
anjolio
Сообщения: 663
Статус: радист
ОС: debian squeeze

Приведение int к указателю в С

Сообщение anjolio »

Начинаю изучать С. Возникла следующая проблема.
Код:
librename.c

Код: Выделить всё

  1 int get_name_addition ()
  2 {
  3   /* Инициализация переменных */
  4   char name[100];
  5   /* Тело функции */
  6   printf("Введите последовательность символов, которую\n");
  7   printf("необходимо будет добавить к именам файлов...");
  8   fgets(name,100,stdin);
  9   return *name;
 10 }

main.c

Код: Выделить всё

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include "librename.c"
  5 int main ()
  6 {
  7   char *a=0;
  8   a = get_name_addition();
  9   printf("%s\n",&a);
 10   return 0;
 11 }


При компиляции получаю следующее:

Код: Выделить всё

anjolio@desktop:~/Разработка/renamer$ gcc main.c
main.c: In function ‘main’:
main.c:8: warning: assignment makes pointer from integer without a cast


Покопался гуглом, на супостатских сайтах пишут, что это специфично для gcc, а во всяких MS Visual C++ и т.п. всё компилится..

Код: Выделить всё

$ apt-cache show gcc | grep Version
Version: 4:4.3.2-2

Так вот, внимание вопрос! Как привести int к указателю?
The two most common things in the Universe are hydrogen and stupidity. (Harlan Ellison)
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Приведение int к указателю в С

Сообщение serzh-z »

Жесть... =)

anjolio писал(а):
09.01.2009 13:12
Так вот, внимание вопрос! Как привести int к указателю?
Во-первых - зачем? Если a и так указатель.

Во-вторых, приложение рано или поздно свалится в обработчик SIGSEGV при обращении к a после разрушения кадра стека для функции get_name_addition. Нельзя возвращать из функции указатель на стековую переменную name.
Спасибо сказали:
Аватара пользователя
anjolio
Сообщения: 663
Статус: радист
ОС: debian squeeze

Re: Приведение int к указателю в С

Сообщение anjolio »

serzh-z писал(а):
09.01.2009 13:47
Нельзя возвращать из функции указатель на стековую переменную name.

Потому что после выхода из функции она разрушается?
Тогда я создаю name как static, всё равно ничего не меняется..
The two most common things in the Universe are hydrogen and stupidity. (Harlan Ellison)
Спасибо сказали:
Аватара пользователя
gluk47
Сообщения: 297
Статус: Любитель гвоздей и микроскопов
ОС: Kubuntu 17.10

Re: Приведение int к указателю в С

Сообщение gluk47 »

Во-первых, да.
Во-вторых, например, можно так:

Код: Выделить всё

  1 char* get_name_addition ()
  2 {
  3   /* Инициализация переменных */
  4   char* name=malloc (100); /*100 байт*/
  5   /* Тело функции */
  6   printf("Введите последовательность символов, которую\nнеобходимо будет добавить к именам файлов...");
  7   fgets(name,100,stdin);
  8   return name;
  9 }

  5 int main ()
  6 {
  7   char *a=get_name_addition();
  8   printf("%s\n",a);
  9   return 0;
10 }


А ещё всякие там микрософт - это c++, там более строгая типизация и так компилироваться и не должно (не warning, а error), проверьте в g++ :) .
...Ах да, это же по стандарту, я забыл, что мы про микрософт :rolleyes:
[gluk47@gluk47-desktop ~]$ ензу куищще
куищще is aliased to `reboot'
Спасибо сказали:
Аватара пользователя
whirlwind
Сообщения: 67

Re: Приведение int к указателю в С

Сообщение whirlwind »

anjolio писал(а):
09.01.2009 13:12

Код: Выделить всё

anjolio@desktop:~/Разработка/renamer$ gcc main.c
main.c: In function ‘main’:
main.c:8: warning: assignment makes pointer from integer without a cast


Вы получаете предупреждение, оно должно вас защитить, если ві вдруг забыли там звездочку в нужном месте поставить. Например

Код: Выделить всё

  int* someIntPtr;
   int  someIntValue = 42;

   someIntValue = someIntPtr; // на самом деле здесь хотели  *someIntPtr


Напишете у себя

Код: Выделить всё

a = (char*)get_name_addition();
и предупреждение исчезнет

А то, что, сама функция неправильна, нельзя так с памятью работать -- это отдельно
Добро всегда побеждает зло. Мы победили, значит мы - добро.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Приведение int к указателю в С

Сообщение serzh-z »

gluk47
Память течёт, а нам не жалко... Благо, что у этого приложения всё равно короткий срок жизни. =)
Спасибо сказали:
Аватара пользователя
gluk47
Сообщения: 297
Статус: Любитель гвоздей и микроскопов
ОС: Kubuntu 17.10

Re: Приведение int к указателю в С

Сообщение gluk47 »

Виноват, поспешил) Да, в конец main надо дописать free (a), а в комментарий к функции, что необходимо чистить возвращаемую память :(((
Слишком привык к valgrind'у :(
[gluk47@gluk47-desktop ~]$ ензу куищще
куищще is aliased to `reboot'
Спасибо сказали:
Аватара пользователя
anjolio
Сообщения: 663
Статус: радист
ОС: debian squeeze

Re: Приведение int к указателю в С

Сообщение anjolio »

Всем спасибо!
Создал во внешней функции перменную, а во внутреннюю передал указалтель на неё. Так заработало без предупреждений.

Это и есть борьба с утечками памяти? :)
The two most common things in the Universe are hydrogen and stupidity. (Harlan Ellison)
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Приведение int к указателю в С

Сообщение serzh-z »

anjolio писал(а):
09.01.2009 14:36
Это и есть борьба с утечками памяти? smile.gif
тут возникает другая проблема - глобальные переменные - ЗЛО! =)
Спасибо сказали:
Аватара пользователя
anjolio
Сообщения: 663
Статус: радист
ОС: debian squeeze

Re: Приведение int к указателю в С

Сообщение anjolio »

Так, и каков же выход?

Глобальная переменная - зло
Локальная умирает не успев отработать
Статическая?
The two most common things in the Universe are hydrogen and stupidity. (Harlan Ellison)
Спасибо сказали:
Аватара пользователя
AestheteAnimus
Сообщения: 135
ОС: FreeBSD 8.0-RELEASE amd64

Re: Приведение int к указателю в С

Сообщение AestheteAnimus »

Как правило встречаются такие способы передачи данных из функции.

Во-первых, можно в функции создать статический массив в функции, а потом возращать указатель на него. Как то так:

Код: Выделить всё

#define MAXLINE 100
char* get_name_addition(void)
{
    static char name[MAXLINE];
    fgets(name,MAXLINE,stdin);
    ... // Какие-то дополнительные действия
    return *name;
}


Типичная практика для Unix-а (насколько могу судить), но, как нетрудно заметить, это функция не совместима с многопоточным программированием. Эту функцию можно переделать для многопоточных приложений, используя собственные данные потоков (Thread-Specific Data), но лучше сразу делать иначе.

Пожалуй самая распространенная практика - это передать в функцию буфер для записи - этот буфер не будет привязан к стеку выполняемой функции.

Код: Выделить всё

#define MAXLINE 100
int get_name_addition(char *name, size_t n)
{
    fgets(name, n, stdin);
    ...
    return 0;
}


Не всегда можно заранее угадать, сколько нужно выделить места для буфера - это подчас известно только в вызываемой функции. К примеру в Win эта задача часто решается повторным вызовом одной функции: первый раз задаем нулевой буфер и узнаем необходимый размер; второй раз вызывает функцию с буфером достаточного размера и получаем в него данные. Здесь, в никсах, мне такого не попадалось.

Но встречается более простой способ. В вызываемой функции malloc-ом создаем буфер. Но для его очистки создаем еще одну дополнительную функцию.

Код: Выделить всё

#define MAXLINE 100
char* get_name_addition(void)
{
    char* name;
    name = (char*)malloc(MAXLINE);
    fgets(name, MAXLINE, stdin);
    ...
    return name;
}

void get_name_free(char* name)
{
    free(name);
}


Соответственно, использовать это надо так:

Код: Выделить всё

int main(void)
{
    char *name;
    name = get_name_addition();
    // Что-то делаем
    ...

    get_name_free(name);

    return 0;
}


Конечно, в данном случае можно было бы в main-е просто вызвать free. Но, во первых, возращаемые данные не обязательно будут линейным куском памяти, а могут оказаться каким нибудь связным списком. Во-вторых, если функция та находится в разделяемой библиотеке, я бы не стал исключать случай, что там могла быть слинкована другая реализация malloc-а.
Спасибо сказали:
Аватара пользователя
anjolio
Сообщения: 663
Статус: радист
ОС: debian squeeze

Re: Приведение int к указателю в С

Сообщение anjolio »

AestheteAnimus, огромное спасибо! Всё понятно и по полочкам!
The two most common things in the Universe are hydrogen and stupidity. (Harlan Ellison)
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Приведение int к указателю в С

Сообщение serzh-z »

Эээ... К чему такие сложности?

Кто запрещает передать в get_name_addition указатель на буфер?

Код: Выделить всё

char p[100];

if (get_name_addition(p)) {
  printf("%s\n", p);
}


P.S. опоздал.
Спасибо сказали:
Аватара пользователя
AestheteAnimus
Сообщения: 135
ОС: FreeBSD 8.0-RELEASE amd64

Re: Приведение int к указателю в С

Сообщение AestheteAnimus »

anjolio писал(а):
09.01.2009 15:45
AestheteAnimus, огромное спасибо! Всё понятно и по полочкам!

Ну это всегда пожалуйста :)

serzh-z писал(а):
09.01.2009 15:46

Код: Выделить всё

char p[100];
if (get_name_addition(p)) {
}

Вообще-то, так делать не совсем корректно (да, я знаю, что зануда :tongue: ) - вызываемая функция должна знать размер буфера.
Спасибо сказали:
Ответить