Есть ли в Python какие-либо ключевые слова объявления?

Хотя у вас уже есть ответ для вашего SegFault, существуют дополнительные области, в которых вы можете очистить и реорганизовать свой код для более эффективной совместной работы. Поскольку вы используете структуру списка liste для хранения указателя на начало списка в first, вы также можете добавить еще один указатель last, чтобы указать на последний узел в списке, и избавиться от необходимости повторяться в последний узел на каждой вставке. С указателем last (или tail) ваш новый узел всегда вставляется в last->next. Например, ваша структура Liste может иметь вид:

typedef struct Liste Liste;

struct Liste {
    Element *first, *last;
};

Ваши функции списка должны выполнять одну вещь, то есть initialize() должна просто выделять и инициализировать узел Liste и его указатели. read() должен выделять, читать и возвращать действительный указатель на заполненный узел или NULL в случае сбоя. insert() должен сделать именно это, взять адрес списка Liste и узел из read() и вставить его в список. Соединяя эти функции вместе, вы можете сделать:

Element *read()
{
    Element *element = malloc (sizeof(*element));   /* allocate */
    if (element == NULL)                            /* validate */
        return NULL;
    element->next = NULL;                           /* initialize */

    printf ("\nPlease provide first name : ");
    if (scanf ("%9s", element->f_name) != 1)   /* validate EVERY input */
        goto badread;

    printf ("Please provide last name  : ");
    if (scanf ("%9s", element->l_name) != 1)
        goto badread;

    printf ("Please provide score      : ");
    if (scanf ("%f", &element->score) != 1)
        goto badread;

    return element;     /* return allocated and initialized element */

badread:;     /* just a simple goto label for handling read error */

    free (element);     /* free memory of node if error */

    return NULL;
}

( примечание: использование goto, чтобы отправить вас на метку за пределами обычного возврата, где вы можете освободить память для узел, который потерпел неудачу во время заполнения.)

/* initialize the list, don't worry about the elements */
Liste *initialize (void)
{
    Liste *liste = malloc(sizeof *liste);
    if (liste == NULL) {
        perror ("malloc-liste");    /* give some meaningful error */
        exit (EXIT_FAILURE);
    }
    liste->first = liste->last = NULL;

    return liste;
}

void insert (Liste *liste, Element *nouveau)
{
    if (liste == NULL || nouveau == NULL)
        exit (EXIT_FAILURE);

    if (!liste->first)                          /* inserting 1st node */
        liste->first = liste->last = nouveau;
    else {                                      /* inserting all others */
        liste->last->next = nouveau;
        liste->last = nouveau;
    }
}

( примечание: инициализация и вставка являются прямыми, единственными двумя классами, с которыми вы обращаетесь, является то, вставляете ли вы 1-й узел или все другие узлы. Делает это очень простым)

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN 10     /* if you need a constant, #define one (or more) */

typedef struct Element Element;

struct Element {
    char f_name[MAXN];
    char l_name[MAXN];
    float score;
    Element* next;
};

typedef struct Liste Liste;

struct Liste {
    Element *first, *last;
};

Element *read()
{
    Element *element = malloc (sizeof(*element));   /* allocate */
    if (element == NULL)                            /* validate */
        return NULL;
    element->next = NULL;                           /* initialize */

    printf ("\nPlease provide first name : ");
    if (scanf ("%9s", element->f_name) != 1)   /* validate EVERY input */
        goto badread;

    printf ("Please provide last name  : ");
    if (scanf ("%9s", element->l_name) != 1)
        goto badread;

    printf ("Please provide score      : ");
    if (scanf ("%f", &element->score) != 1)
        goto badread;

    return element;     /* return allocated and initialized element */

badread:;     /* just a simple goto label for handling read error */

    free (element);     /* free memory of node if error */

    return NULL;
}

/* initialize the list, don't worry about the elements */
Liste *initialize (void)
{
    Liste *liste = malloc(sizeof *liste);
    if (liste == NULL) {
        perror ("malloc-liste");    /* give some meaningful error */
        exit (EXIT_FAILURE);
    }
    liste->first = liste->last = NULL;

    return liste;
}

void insert (Liste *liste, Element *nouveau)
{
    if (liste == NULL || nouveau == NULL)
        exit (EXIT_FAILURE);

    if (!liste->first)                          /* inserting 1st node */
        liste->first = liste->last = nouveau;
    else {                                      /* inserting all others */
        liste->last->next = nouveau;
        liste->last = nouveau;
    }
}

void prnlist (Liste *liste)
{
    Element *iter = liste->first;

    while (iter) {  /* just iterate list outputting values */
        printf ("%-10s %-10s  ->  %.2f\n", 
                iter->f_name, iter->l_name, iter->score);
        iter = iter->next;
    }
}

void freelist (Liste *liste)
{
    Element *iter = liste->first;

    while (iter) {
        Element *victim = iter;
        iter = iter->next;          /* iterate to next node BEFORE */
        free (victim);              /* you free victim */
    }
    free (liste);
}

int main (void) {

    Liste *maListe = initialize();  /* create/initialize list */
    Element *node;

    while ((node = read()))         /* allocate/read */
        insert (maListe, node);     /* insert */

    puts ("\n\nElements in list:\n");   /* output list values */
    prnlist (maListe);

    freelist (maListe);     /* don't forget to free what you allocate */

    return 0;
}

Пример использования / вывода

$ ./bin/ll_liste

Please provide first name : Donald
Please provide last name  : Duck
Please provide score      : 99.2

Please provide first name : Minnie
Please provide last name  : Mouse
Please provide score      : 99.7

Please provide first name : Pluto
Please provide last name  : Dog
Please provide score      : 83.5

Please provide first name :

Elements in list:

Donald     Duck        ->  99.20
Minnie     Mouse       ->  99.70
Pluto      Dog         ->  83.50

Использование памяти / проверка ошибок

[ 1131] В любом написанном вами коде, который динамически выделяет память, у вас есть 2 обязанности в отношении любого выделенного блока памяти: (1) всегда сохраняет указатель на начальный адрес для блока память так, (2) он может быть освобожден , когда он больше не нужен.

Крайне важно, чтобы вы использовали программу проверки ошибок памяти, чтобы гарантировать, что вы не пытаетесь получить доступ к памяти или писать за пределами / за пределами выделенного блока, пытаться прочитать или основать условный переход на неинициализированном значении и, наконец, , чтобы подтвердить, что вы освобождаете всю выделенную память.

Для Linux valgrind является нормальным выбором. Для каждой платформы есть похожие проверки памяти. Все они просты в использовании, просто запустите вашу программу через него.

$ valgrind ./bin/ll_liste
==10838== Memcheck, a memory error detector
==10838== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10838== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==10838== Command: ./bin/ll_liste
==10838==

Please provide first name : Donald
Please provide last name  : Duck
Please provide score      : 99.2

Please provide first name : Minnie
Please provide last name  : Mouse
Please provide score      : 99.6

Please provide first name : Pluto
Please provide last name  : Dog
Please provide score      : 87.2

Please provide first name :

Elements in list:

Donald     Duck        ->  99.20
Minnie     Mouse       ->  99.60
Pluto      Dog         ->  87.20
==10838==
==10838== HEAP SUMMARY:
==10838==     in use at exit: 0 bytes in 0 blocks
==10838==   total heap usage: 5 allocs, 5 frees, 144 bytes allocated
==10838==
==10838== All heap blocks were freed -- no leaks are possible
==10838==
==10838== For counts of detected and suppressed errors, rerun with: -v
==10838== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.

Посмотрите вещи и дайте мне знать, если у вас есть вопросы.

11
задан jfs 20 March 2009 в 08:32
поделиться

5 ответов

Мне действительно нравится понимание, что Van Gale обеспечивает, но это действительно не отвечает на вопрос, "как делают Вы знаете если этот оператор: создает новую переменную или устанавливает существующую переменную?"

Если Вы хотите знать, как распознать его при рассмотрении кода, Вы просто ищете предыдущее присвоение. Избегайте глобальных переменных, который является хорошей практикой так или иначе, и Вы будете все установлены.

Программно, Вы могли попытаться сослаться на переменную и видеть, получаете ли Вы "Ошибочное исключение" Имени

try:
    x
except NameError:
    # x doesn't exist, do something
else:
    # x exists, do something else

Я никогда не должен был делать этого..., и я сомневаюсь, что Вы действительно должны будете также.

предупреждение мыльницы!!!

Даже при том, что Python смотрит вид loosey-goosey кому-то, кто привык иметь необходимость ввести имя класса (или тип) много раз, и... это на самом деле точно столь строго, как Вы хотите сделать его.

Если бы Вы хотите строгие типы, Вы сделали бы это explictly:

assert(isinstance(variable, type))

Декораторы существуют, чтобы сделать это очень удобным способом для вызовов функции...

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

Я в настоящее время работаю в actionscript и ввожу вещи как:

var win:ThingPicker = PopUpManager.createPopUp(fEmotionsButton, 
       ThingPicker, false) as ThingPicker;

который в Python был бы похож:

win = createPopup(parent, ThingPicker)

И я вижу, смотря на код ActionScript, что нет просто никакого преимущества для статической проверки типа. Время жизни переменной так коротко, что я должен был бы быть абсолютно пьяный, чтобы сделать, неправильная вещь с ним... и иметь компилятор сохраняет меня путем указания на ошибку типа.

15
ответ дан 3 December 2019 в 01:03
поделиться

Стоит упомянуть, что существует глобальное ключевое слово, поэтому если Вы хотите обратиться к глобальному x:

x = 4
def foo():
    x = 7 # x is local to your function

Необходимо сделать это:

x = 4
def foo():
    global x # let python know you want to use the top-level x
    x = 7
12
ответ дан 3 December 2019 в 01:03
поделиться

Не похоже, что автор вопроса пытается присвоить тип, только указать что это объявление, не присвоение.

Похож на Вас, ищут, что-то как JavaScript имеет:

var x = 5;

Понятие ключевого слова объявления в JavaScript состоит в том, чтобы гарантировать, что Вы делаете новый объект в текущей области и просто не заменяете некоторый другой того же имени.

Python не имеет этой функции. Программист должен удостовериться, что не повторно присваивает существующие ранее имена.

7
ответ дан 3 December 2019 в 01:03
поделиться

Важная вещь понять о Python нет никаких переменных, только "имена".

В Вашем примере у Вас есть объект "5", и Вы создаете имя "x" что ссылки объект "5".

Если позже Вы делаете:

x = "Some string"

это все еще совершенно допустимо. Имя "x" теперь указывает для возражения "Некоторой строке".

Это не конфликт типов, потому что само имя не имеет типа, только объект.

При попытке x = 5 + "Некоторая строка", Вы получите ошибку типа, потому что Вы не можете добавить два несовместимых типа.

Другими словами, это не свободный тип. Объекты Python со строгим контролем типов.

Вот некоторые очень хорошие дискуссии о вводе Python:

Править: чтобы закончить согласоваться это в Вашем вопросе, имя может сослаться на существующий объект или новый.

# Create a new int object
>>> x = 500
# Another name to same object
>>> y = x
# Create another new int object    
>>> x = 600
# y still references original object
>>> print y
500
# This doesn't update x, it creates a new object and x becomes
# a reference to the new int object (which is int because that
# is the defined result of adding to int objects).
>>> x = x + y
>>> print x
1100
# Make original int object 500 go away
>>> del y

Редактирование 2: самое полное обсуждение различия между изменяемыми объектами (который может быть изменен) и неизменные объекты (который не может быть изменен) в официальная документация Модели данных Python.

14
ответ дан 3 December 2019 в 01:03
поделиться

Я только что понял, что есть более прямой ответ тоже:

x = 5

def test():
    print 'x' in globals()

if __name__ == "__main__":
    test()

, так что если «Variablename» в глобалях (): Заявление является заданием иначе Заявление является декларацией

0
ответ дан 3 December 2019 в 01:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: