адрес указателя символа [дубликат]

Феликс уже дал отличный ответ, но я думал, что сделаю сравнение скорости различных методов:

  1. 10,59 сек (105,9us / itn) - copy.deepcopy(old_list)
  2. 10.16 сек (101.6us / itn) - метод чистого питона Copy(), копирующий классы с глубокой копией
  3. 1.488 сек (14.88us / itn) - чистый питон Copy() метод не копирует классы (только dicts / lists / tuples)
  4. 0,325 с (3,25us / itn) - for item in old_list: new_list.append(item)
  5. 0.217 sec (2.17us / itn) - [i for i in old_list] (понимание списка )
  6. 0,186 с (1,86us / itn) - copy.copy(old_list)
  7. 0,075 сек (0,75 us / itn) - list(old_list)
  8. 0,053 сек (0,53us / itn) - new_list = []; new_list.extend(old_list)
  9. 0,039 сек (0,39us / itn) - old_list[:] ( list slicing )

Таким образом, самая быстрая сортировка списка. Но имейте в виду, что copy.copy(), list[:] и list(list), в отличие от copy.deepcopy() и версии python, не копируют списки, словари и экземпляры класса в списке, поэтому, если оригиналы меняются, они будут меняться в скопированный список тоже и наоборот.

(Вот скрипт, если кто-то заинтересован или хочет поднять какие-либо проблемы:)

from copy import deepcopy

class old_class:
    def __init__(self):
        self.blah = 'blah'

class new_class(object):
    def __init__(self):
        self.blah = 'blah'

dignore = {str: None, unicode: None, int: None, type(None): None}

def Copy(obj, use_deepcopy=True):
    t = type(obj)

    if t in (list, tuple):
        if t == tuple:
            # Convert to a list if a tuple to 
            # allow assigning to when copying
            is_tuple = True
            obj = list(obj)
        else: 
            # Otherwise just do a quick slice copy
            obj = obj[:]
            is_tuple = False

        # Copy each item recursively
        for x in xrange(len(obj)):
            if type(obj[x]) in dignore:
                continue
            obj[x] = Copy(obj[x], use_deepcopy)

        if is_tuple: 
            # Convert back into a tuple again
            obj = tuple(obj)

    elif t == dict: 
        # Use the fast shallow dict copy() method and copy any 
        # values which aren't immutable (like lists, dicts etc)
        obj = obj.copy()
        for k in obj:
            if type(obj[k]) in dignore:
                continue
            obj[k] = Copy(obj[k], use_deepcopy)

    elif t in dignore: 
        # Numeric or string/unicode? 
        # It's immutable, so ignore it!
        pass 

    elif use_deepcopy: 
        obj = deepcopy(obj)
    return obj

if __name__ == '__main__':
    import copy
    from time import time

    num_times = 100000
    L = [None, 'blah', 1, 543.4532, 
         ['foo'], ('bar',), {'blah': 'blah'},
         old_class(), new_class()]

    t = time()
    for i in xrange(num_times):
        Copy(L)
    print 'Custom Copy:', time()-t

    t = time()
    for i in xrange(num_times):
        Copy(L, use_deepcopy=False)
    print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t

    t = time()
    for i in xrange(num_times):
        copy.copy(L)
    print 'copy.copy:', time()-t

    t = time()
    for i in xrange(num_times):
        copy.deepcopy(L)
    print 'copy.deepcopy:', time()-t

    t = time()
    for i in xrange(num_times):
        L[:]
    print 'list slicing [:]:', time()-t

    t = time()
    for i in xrange(num_times):
        list(L)
    print 'list(L):', time()-t

    t = time()
    for i in xrange(num_times):
        [i for i in L]
    print 'list expression(L):', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(L)
    print 'list extend:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        for y in L:
            a.append(y)
    print 'list append:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(i for i in L)
    print 'generator expression extend:', time()-t

EDIT: добавлены классы старого стиля и задает тесты, и сделал версию python намного быстрее и добавил еще несколько методов, включая выражения списков и extend().

40
задан Garrett 8 July 2014 в 05:19
поделиться

5 ответов

«hello» - это строка, то есть массив символов. const char* является указателем на этот массив, поэтому, когда вы разыгрываете этот указатель, вы получаете значение первого элемента.

Как будто у вас есть

int a[] = {1, 2, 3};
int *b = a;
cout << *b << endl;

, вы просто напечатайте 1.

-1
ответ дан Ivan Smirnov 22 August 2018 в 03:39
поделиться
  • 1
    почему я не получаю адрес памяти? – Mr.Puff 23 July 2013 в 15:45
  • 2
    @ Mr.Puff Если вы хотите получить адрес памяти указателя char, вы должны указать его на указатель void раньше, потому что оператор ostream << перегружен для указателей на символы для печати строк. – Ivan Smirnov 23 July 2013 в 15:48

Оператор << на std::cout перегружен. Его поведение зависит от типа правильного операнда. (Это фактически несколько разных функций, все названы operator<<, компилятор решает, какой из них вызывать.)

Если вы дадите ему char* или const char*, он обрабатывает операнд как указатель на (первый символ) строки C-стиля и печатает содержимое этой строки:

const char * terry = "hello";
cout << terry; // prints "hello"

Если вы даете ему значение char, оно печатает это значение как символ:

cout << *terry;   // prints "h"
cout << terry[0]; // the same

Если вы указали ему указатель типа void*, он печатает это значение указателя (в определенном порядке реализации, обычно шестнадцатеричном):

cout << static_cast<const void*>(terry); // prints something like 0x4008e4

Обработка char* или const char* как указатель на строку C-стиля - это особый случай, и единственное, что я могу придумать, которое вызывает operator<< для печати чего-то другого, кроме значения операнда. Причина этого восходит к корням C ++ в C, который не имеет типа «string» и манипулирует строками с помощью указателей char*.

Существует множество других перегрузок для operator<<, для различных целочисленные и числовые типы с плавающей запятой, для std::string и т. д.

14
ответ дан Keith Thompson 22 August 2018 в 03:39
поделиться

Причиной этого является то, что std::cout будет обрабатывать char * как указатель на (первый символ) строки стиля C и печатать его как таковой. Если вы хотите использовать адрес , вы можете просто передать его указателю, который не был обработан таким образом, например:

cout << (void *) terry;

(или используйте бросок const void *, если вы беспокоитесь о том, чтобы отбросить созвездие, что-то, что не является проблемой в данном конкретном случае).


Если вы скорее пурист, чем прагматик, вы также можете использовать C ++ static_cast по строкам:

cout << static_cast <const void *> (terry);

, хотя в этом конкретном случае это необязательно, приведение к void * будет работать нормально. Следующий пример кода показывает все эти параметры в действии:

#include <iostream>
int main (void) {
    const char *terry = "hello";
    std::cout << terry << '\n';
    std::cout << (void *) terry << '\n';
    std::cout << (const void *) terry << '\n';
    std::cout << static_cast<const void *> (terry) << '\n';
    return 0;
}

вывод (адрес может быть другим в вашей среде):

hello
0x8048870
0x8048870
0x8048870

Обратите внимание, что при использовании кнопки static_cast, вы должны убедиться, что вы не пытаетесь отбросить константу с помощью static_cast <void *> (это для const_cast). Это одна из проверок, выполненных более новыми C ++-переходами, и старинный стиль не имеет этого ограничения.

58
ответ дан paxdiablo 22 August 2018 в 03:39
поделиться
  • 1
    Он не рассматривает значение char* как строку стиля C; он рассматривает его как указатель для (первого символа) строки стиля C. – Keith Thompson 23 July 2013 в 15:47
  • 2
    @Keith, проблема семантики, извинения за это. Я имел в виду, что он печатает его как строку стиля C. Я уточню. – paxdiablo 23 July 2013 в 15:48
  • 3
    @Keith, нет, это не означало быть несущественным (иначе я бы не изменил его). Я имел в виду, что я не понял своего смысла так же хорошо, как должен. Надеюсь, изменения исправили это. – paxdiablo 23 July 2013 в 15:53
  • 4
    Это опасно только тем, кто не знает, что они делают. В этом случае выпадение константы не имеет значения, так как вы ничего не делаете с указателем, где это имеет значение. Да, если бы вы набросили указатель, то ушли и использовали его неправильно, я бы согласился, но я ожидаю, что практикующие изучают язык, чтобы использовать его безопасно. Я не позволил сыну начать использовать мои более опасные инструменты, пока он не доказал, что знает проблемы с ними :-) – paxdiablo 23 July 2013 в 16:04
  • 5
    Вы говорите об лени, как будто это bad . Это плохо, если есть фактический декрементальный эффект, иначе он известен как эффективность. Нет проблем с использованием статических прикладов в данной конкретной ситуации , и они являются такой же частью языка C ++, как и любая другая (даже такие вещи, как cstdio, приемлемы, если вы понимаете проблемы). – paxdiablo 23 July 2013 в 23:09

cout перегружен, так что, когда вы даете ему char *, он будет печататься как указатель на строку стиля C. Таким образом, он печатает символы до тех пор, пока не ударит нулевой завершающий символ.

Если вы использовали printf вместо cout, вы увидите адрес. Вы также можете направить указатель на другой тип, скажем (void *), и вы также получите адрес.

1
ответ дан Richard Fung 22 August 2018 в 03:39
поделиться
  • 1
    printf сам не решает, как он печатает, вам все равно придется использовать правильный спецификатор формата, так же, как вы должны использовать тот же тип в C ++. Например, printf с %s будет иметь ту же проблему, что и cout с char *. Чтобы получить указатель, вы должны использовать спецификатор формата %p. – paxdiablo 4 July 2015 в 04:52

Вы должны изменить свой код на это:

cout << static_cast<const void*>(terry);

Проблема в том, что оператор << перегружен для указателей на строки C-стиля для печати содержимого строки. Если вы вместо этого нарисуете его на необработанный указатель, вы будете иметь поведение по умолчанию для указателя печати, используя iostreams, как вы хотите.

8
ответ дан sasha.sochka 22 August 2018 в 03:39
поделиться
Другие вопросы по тегам:

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