Вставка строки в стек возвращает случайный символ

Работаю над помещением строки в мой стек, и в настоящее время я получаю случайные символы (символы не помещаются в стек, потому что, когда я потом проверяю, мой стек пуст)

вот соответствующие функции и структура

typedef char stackitem;

struct stack {
stackitem  d;
struct stack *next;
};

typedef  struct stack ELEMENT;
typedef  ELEMENT   *POINTER;

void push(POINTER *Top, stackitem a)
/* Put item a into the top of the stack */
     {
        POINTER temp;
        temp = malloc(sizeof(ELEMENT));
        temp->d = a;
        temp->next = *Top;
        *Top = temp;
        printf("Insert element %c\n", temp->d);
     }
void push_string(POINTER *Top,char *string)
/* Push a string of characters into a stack. */
    {
        char *tmp = malloc(strlen(string) + 1);
        if (tmp)
        strcpy(tmp, string);
    push(&Top,tmp);

Части второй функции я нашел в другом потоке SO. И вот как я его использую:

main()
    {
    POINTER top;
        top= (POINTER) NULL;
        stackitem A='A';
        stackitem B='B';
        char *C="12345";
        push_string(&top,C);
        print_stack(top);

        return 0;
   }
      

Как я могу добавить строку в стек? функция push работает для помещения символов в стек, но я не могу заставить ее нажать целую строку.


person william_    schedule 10.03.2021    source источник
comment
По-видимому, ваш стек (определение которого вы не показываете) может содержать символы, но не строки. Один из способов поместить всю строку в стек — это поместить все символы, поэтому вместо того, чтобы пытаться поместить "ABC", выполните цикл по строке и поместите 'A', 'B' и 'C'.   -  person M Oehm    schedule 10.03.2021
comment
Я обновил свой пост для определений ... не будет ли цикл по строке выдвигать каждый символ как отдельный элемент в стеке? это для некоторых задач uni, и я считаю, что цель состоит в том, чтобы поместить строку в стек   -  person william_    schedule 10.03.2021
comment
Делать typedef ELEMENT *POINTER; считается плохой практикой. Используйте ELEMENT*, чтобы читатель мог видеть, что это указатель.   -  person ikegami    schedule 10.03.2021
comment
Этот код не предупреждает? Мне кажется, компилятор сразу бы нашел проблему! Обязательно включите предупреждения вашего компилятора (например, -Wall -Wextra -pedantic с gcc/clang)   -  person ikegami    schedule 10.03.2021
comment
@william_ Функция push_string не имеет смысла.   -  person Vlad from Moscow    schedule 10.03.2021
comment
Да, зацикливание вытолкнет символы как отдельные элементы. (Поскольку ваше сообщение было не очень ясным, я позволил себе догадаться об этом.) Вы можете сделать так, чтобы стек принимал как строки, так и символы, например, с помеченным объединением в качестве элемента стека. Но тогда код, который извлекает данные из стека, также должен различать строки и символы. Другая возможность - превратить символы в строки из 1 буквы.   -  person M Oehm    schedule 10.03.2021
comment
Если вам нужен стек, в котором хранятся только строки, вы должны принять свой тип элемента. Если у вас есть несколько стопок, в которых могут храниться разные предметы, вам нужны CharStack, IntStack, StringStack и так далее. C++ и многие другие языки позволяют вам использовать шаблоны, так что вы можете сказать stack<char>, а компилятор под капотом создаст для вас CharStack.   -  person M Oehm    schedule 10.03.2021
comment
Почему вы удалили весь свой код из вопроса?   -  person Barmar    schedule 11.03.2021


Ответы (2)


Во-первых, включите все предупреждения (опции -Wall -pedantic). Компилятор, скорее всего, будет жаловаться на приведение несовместимых типов.

Функция push() предназначена для помещения в стек одного char, тогда как push_string() предназначена для помещения всех символов string один за другим.

Поэтому, чтобы поместить строку, вы должны поместить каждый символ строки отдельно.

void push_string(POINTER *Top,char *string) {
  for (char *s = string; *s; ++s)
    push(Top, *s);
}
person tstanisl    schedule 10.03.2021
comment
быстрый вопрос о цикле, что означает условие *s; представлять? - person william_; 10.03.2021
comment
@william_, *s проверяет символ, на который указывает s. Цикл продолжается до тех пор, пока не встретится 0-значение (ограничитель строки). Значение 0 равно false в C. - person tstanisl; 10.03.2021

Фрагмент кода функции push_string как есть не имеет смысла.

Например, нет необходимости создавать копию переданной строки.

    char *tmp = malloc(strlen(string) + 1);
    if (tmp)
    strcpy(tmp, string);

Во-вторых, этот звонок

push(&Top,tmp);

имеет недопустимые типы аргументов.

Функция push_string может выглядеть следующим образом

void push_string( POINTER *Top, const char *string )
{
    for ( ; *string; ++string ) push( Top, *string );
}

Вот демонстрационная программа.

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

typedef char stackitem;

struct stack {
stackitem  d;
struct stack *next;
};

typedef  struct stack ELEMENT;
typedef  ELEMENT   *POINTER;

int push( POINTER *Top, stackitem c )
{
    POINTER temp = malloc( sizeof( ELEMENT ) );
    int success = temp != NULL;
    
    if ( success )
    {
        temp->d = c;
        temp->next = *Top;
        *Top = temp;
    }
    
    return success;
}

void push_string( POINTER *Top, const char *string )
{
    for ( ; *string; ++string ) push( Top, *string );
}

int pop( POINTER *Top, stackitem *c )
{
    int success = *Top != NULL;
    
    if ( success )
    {
        *c = ( *Top )->d;
        POINTER temp = *Top;
        *Top = ( *Top )->next;
        free( temp );
    }
    
    return success;
}

int main(void) 
{
    POINTER top = NULL;
    
    push_string( &top, "12345" );
    
    for ( char c; pop( &top, &c ); )
    {
        putchar( c );
    }
    putchar( '\n' );
    
    return 0;
}

Вывод программы

54321

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

В демонстрационной программе функция push сообщает, было ли нажатие элемента успешным.

Функция push_string также должна сообщить, была ли строка успешно отправлена. В этом случае его можно определить следующим образом

int push_string( POINTER *Top, const char *string )
{
    while ( *string && push( Top, *string ) ) ++string;
  
    return *string == '\0';
}

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

person Vlad from Moscow    schedule 10.03.2021