Надеюсь, вы не примете это на свой счет ... но в этом коде так много ошибок на стольких логических уровнях, что, на мой взгляд, это просто FUBAR .
Пожалуйста, сделайте себе одолжение и начните с чтения книги на C ++. Список хороших можно найти здесь , а также вы можете найти бесплатные ресурсы в Интернете.
C ++ - это не тот язык, который вы (или любой другой) можете надеяться выучить, просто набрав на нем несколько символов и посмотрев, что происходит ... это просто суицидальный подход к C ++.
EDIT:
После некоторого поиска в Google кажется, что вы действительно следуете книге. Из нескольких отрывков, которые я нашел в сети, кажется, книга, которая преподает программирование с использованием C ++. Я не думаю, что это хорошая идея, потому что C ++ слишком сложен и, по-видимому, нелогичен, чтобы быть первым языком для программиста, также очень легко получить программы, которые хорошо компилируются, и это просто сведет вас с ума, когда вы их запустите. Однако некоторые гуру считают, что это жизнеспособный подход.
Ваша книга действительно указана не потому, что она хорошая, а потому, что ее название близко к названию хорошей книги. Вероятно, это просто маркетинговый ход, чтобы продать его.
EDIT2:
Мне было немного жаль, что я был настолько груб, когда твоя единственная ошибка - выбрать плохую книгу для изучения C ++. Попытка компенсировать это моя попытка рассказать обо всех проблемах, которые, я думаю, присутствуют в вашем коде C ++:
1. Изучай стандарт C ++
#include "stdafx.h"
Если вы изучаете C ++, вам следует отложить в сторону все, что Microsoft говорит вам о языке. Стандарт C ++ никогда не был важен для Microsoft; вероятно, потому что переносимый код представляет собой скорее угрозу для Microsoft, чем полезен для них.
Как только вы знаете C ++ (но только тогда), можно писать код для Microsoft, если это ваша платформа. Но важно, чтобы вы знали, что такое ms-only и что такое C ++. В некоторых случаях разница просто глупа и не заслуживает рассмотрения (например, for
определение или обработка ошибок выделения), но иногда вы ДОЛЖНЫ использовать их вариант языка для работы с окнами.
Средства разработки MS великолепны (или, по крайней мере, они были ... Я просто влюблен в VC6, например), но они всегда будут пытаться обмануть вас при написании непереносимого кода. Это делается как в IDE, так и в примерах Windows API. Не попадайтесь в эти ловушки: пишите переносимый код, если у вас нет реальной потребности в коде для конкретной платформы, и всегда помните об этом.
2. Не загрязняйте глобальное пространство имен
using namespace std;
Это плохая идея. Даже если это немного раздражает, гораздо лучше, если вы привыкнете писать std::
перед стандартными функциями. Причины кроются в сложных правилах поиска имен и разрешения перегрузки, которые присутствуют в языке, а также из-за всех имен, которые вы вводите в свое пространство имен, не осознавая их.
Экономия времени при наборе на самом деле не так важна в C ++ (это важно в PERL, если вы пишете одноразовый скрипт ... но не для обычных программ). Гораздо важнее помочь тому, кто читает ваш код (включая вас) и использует std::
.
3. Используйте правильное основное объявление
Это опять о том, чтобы не попасть в тупые ловушки MS. Правильное объявление для main -
int main(int argc, const char *argv[])
Вы никогда не должны использовать что-либо еще при изучении C ++. Если инструмент MS, который вы используете, не позволяет вам написать правильное объявление (это не было бы сюрпризом), просто бросьте его прямо сейчас и изучите C ++, используя инструмент, который демонстрирует некоторое уважение к стандарту. Как только вы знаете C ++, вы можете начать использовать непереносимые вещи, если вам действительно нужно, но зная, что это непереносимые вещи.
Mingw - хороший бесплатный компилятор C ++ для Windows, и есть бесплатных хороших IDE , если они вам нравятся. С годами мне нравилось пользоваться хорошим редактором, таким как emacs ( vim тоже хорошо, я использовал его много лет) и компилятором командной строки, но в основном потому, что я работаю на разных языках в нескольких операционных системах, и ни одна IDE не может охватить все это. Я хочу поместить знания низкого уровня (как скопировать фрагмент текста, как искать строку, как попросить завершение, как открыть другой файл) на уровне пальца и не нужно сознательно думать, в какой IDE я нахожусь просто чтобы найти правильную команду. Вы не можете играть Шопена , если вам каждый раз приходится думать, где находится G # на клавиатуре.
Может быть, я просто старый, однако ...; -)
4. Выберите разумное соглашение об именах
struct stringy {
char * str; //points to a string
int ct; //length of string(not counting '\0')
};
В вашем коде вы называете класс stringy
. Будет лучше, если вы привыкнете к тому, что является наиболее распространенным соглашением об именах в C ++ для классов, то есть вместо этого оно называется Stringy
.
Стандартная библиотека C ++ не следует этому соглашению, но эти классы всегда будут иметь префикс std::
.
Мой совет также НЕ использовать идею системной венгерской нотации вызова переменных в зависимости от типа C ++ (например, iIndex
, sFileName
), который иногда присутствует в документации MS. Эта идея не масштабируется и просто означает, что вы будете использовать плохие имена для всех ваших переменных.
5. Проблемы с заданной функцией
void set(stringy & obj, char cstr)
{
char * temp = new char[cstr];
obj.str = temp;
for (int i = 0; i < temp.length(); i++)
temp[i] = cstr[i];
}
В этой функции есть несколько ошибок:
Вы хотите передать char *
, а не char
. char
содержит место для одного символа, и вместо этого вы хотите инициализировать ваш экземпляр stringy
последовательностью символов. В C ++ вы можете использовать для этого указатель на символ, потому что в памяти имеется специальная поддержка последовательностей символов, которые закрываются специальным ascii char NUL (обратите внимание на одиночный "L" , символ ASCII NUL в C ++ пишется '\0'
и его не следует путать с указателем NULL). Предпочтительным способом обработки последовательностей символов в C ++ является стандартный класс std::string
, но последовательности символов, определенные в NUL , также полностью поддерживаются для обратной совместимости с C.
Указатель, однако, является просто адресом символа ... за этим символом будут следовать другие символы, пока вы не найдете закрывающий '\0'
, но указатель не имеет члена length
(на самом деле членов нет все, это примитивный тип, такой как int
или double
).
Чтобы узнать длину последовательности символов, которая была передана с помощью указателя, существует стандартная функция strlen
(которая возвращает количество символов в последовательности , исключая завершающую '\0'
) , Таким образом, ваш код должен выглядеть примерно так:
void set(stringy & obj, char *cstr)
{
char * temp = new char[1 + strlen(cstr)];
obj.str = temp;
strcpy(obj.str, cstr);
}
Я также использовал стандартную функцию strcpy
, которая копирует последовательность символов, включая маркер конца '\0'
. Возможная реализация strcpy
(здесь, чтобы показать идею '\0'
-определенных строк) следующая:
char *mystrcpy(char *dest, const char *src)
{
int i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return dest;
}
6. Распределение памяти
Класс stringy
плохо спроектирован (в C ++ нет большой разницы между struct
и class
: только то, что используется по умолчанию для видимости). Конкретное конструирование и уничтожение не обрабатываются там, где они должны быть (внутри строкового класса), а для класса, спроектированного таким образом, конструирование присвоения и копирования также должно обрабатываться или запрещаться.
Как следствие, ваша программа просто забывает утечку памяти из-за освобождения памяти (обычно это не серьезная проблема для main
, но важно понимать проблему).
Надеюсь, эта проблема только потому, что книга еще не пришла, чтобы объяснить эти концепции.
В любом случае я нахожу странной книгу, которая говорит о new[]
, но не о delete[]
(может быть, есть причина, по которой ваша книга не указана как хорошая книга).
Правильно реализованный stringy
, если IMO будет выглядеть примерно так:
struct stringy
{
int size; // Number of characters EXCLUDING ending '\0'
char *ptr; // Pointer to first character
stringy(const char *s = "")
: size(strlen(s)), ptr(new char[1 + size])
{
strcpy(ptr, s);
}
~stringy()
{
delete[] ptr;
}
stringy(const stringy& other)
: size(other.size), ptr(new char[1 + size])
{
strcpy(ptr, other.ptr);
}
stringy& operator=(const stringy& other)
{
char *newptr = new char[1 + other.size];
strcpy(newptr, other.ptr);
delete[] ptr;
ptr = newptr;
size = other.size;
return *this;
}
};