Значение указателя структуры не изменяется после вызова функции - PullRequest
0 голосов
/ 07 ноября 2018

РЕДАКТИРОВАТЬ *: я знаю, что есть похожие вопросы, но так как это практическое задание, подписи функций даны, и мне разрешено только изменять тела функций. Следовательно, я не могу изменить параметры функции или возвращаемые типы, как, скажем, ответы в похожих темах. Заранее спасибо!

Я действительно запутался в программе, которую пишу. Я в основном пишу функцию, которая берет два указателя на структуры, структуры имеют компонент int и компонент массива символов. Функция добавляет два компонента символьного массива для возврата структуры (что-то вроде strcat). Дело в том, что в то время как часть массива структуры обновляется функцией, часть int - нет. Кто-нибудь может объяснить почему? Функция newText создает новый текст структуры и устанавливает массив структуры в качестве параметра функции. Он также устанавливает емкость = 24. Если длина строкового параметра больше 24, он удваивает емкость, пока не уместится. Функция append добавляет две строки, затем вызывает newText с новой добавленной строкой и устанавливает t1 равным возвращаемому значению newText. У меня есть операторы print в конце функции добавления, чтобы показать мне, что она работает и значения верны, однако в основном после того, как я вызываю функцию, t- >acity снова становится 24 вместо 48, в то время как t-> content является правильным. Вот мой код:

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


struct text { int capacity; char *content; };

typedef struct text text;


text *newText(char *s) {

  text *t = malloc(sizeof(text));
  t->capacity = 24;

  while (strlen(s) + 1 > t->capacity) {t->capacity = t->capacity * 2;} 
  t->content = malloc(t->capacity);
  strcpy(t->content, s);

  return t; 
}

void append(text *t1, text *t2) {
  int length1 = strlen(t1->content);
  int length2 = strlen(t2->content);
  int lengths = length1 + length2;


  for (int i = length1; i < length1 + length2; i++){
  t1->content[i] = t2->content[i - length1];
  t1->content[i + 1] = '\0';                }

  char text[100];
  strcpy(text, t1->content);


  t1 = newText(text);

  printf("%s \n", t1->content);
  printf("%d \n", t1->capacity);

}

int main () {
  text *t = malloc(sizeof(text));
  text *t1 = malloc(sizeof(text));

  t = newText("carpet");
  t1 = newText("789012345678901234");
  append(t, t1);
  printf("%d\n", t->capacity);
}

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

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

    void test(char** ppTest) {
    //Is anything valid passed?
        if ( ppTest == NULL ) {
            return;
        }
        *ppTest = "Hello World";
    }

    int main(void) {
        char* pTest = NULL;
        printf("Before function call pTest: %s\n", (pTest == NULL) ? "NULL" : pTest);
        test(&pTest); // Must pass the address of the pointer
        printf("After function call pTest: %s\n", (pTest == NULL) ? "NULL" : pTest);            
        return 0;
    }
0 голосов
/ 07 ноября 2018
 t1 = newText(text);

Здесь вы устанавливаете t1 на новый text. Однако оригинал text, на который указывал t1, здесь не меняется. Это все еще указывает на то же место. Указатель, который вы передали в функцию, является копией исходного указателя, поэтому, даже если t1 указывает на новый text, оригинал - нет.

Так что, когда вы делаете печать здесь

  printf("%d\n", t->capacity);

Вы по-прежнему получаете старое значение мощности. А точнее, вместимость старого t1. Тогда как здесь

printf("%s \n", t1->content);
printf("%d \n", t1->capacity);

Вы печатаете content и capacity нового t1, на который вы теряете указатель после завершения функции.

Вы можете исправить это, например, вернув этот указатель. Измените подпись на

text* append(text *t1, text *t2)

И в конце функции:

return t1;

А потом вы обновляете t1, поэтому измените это

append(t, t1);

К

t1 = append(t, t1);

Также следите за утечками памяти. Как и сейчас, в append вы берете указатели на два действительных text и выделяете новый text, а в конце функции у вас остается только два указателя на text а вы не free ничего. Это показывает нам, что один из них просочился.

Edit:

Если вы не можете изменить сигнатуру функции, вы не можете вернуть новый text или передать его с помощью двойного указателя. В этом случае я бы предложил не создавать новый text, а просто изменить t1. Используя realloc, вы можете изменить размер буфера (на самом деле, он может просто выделить новый буфер, скопировать данные и освободить старый буфер), чтобы вы могли добавить содержимое t2.

void append(text *t1, text *t2) {
    int length1 = strlen(t1->content);
    int length2 = strlen(t2->content);
    int lengths = length1 + length2;                // calculate the required length. You can change this to have some "reserve" such as in newText. In this example, it will be 24

    t1->content = realloc(t1->content, lengths);        // set the correct size for the buffer

    for (int i = length1; i < length1 + length2; i++) {
        t1->content[i] = t2->content[i - length1];
        t1->content[i + 1] = '\0';
    }   // append the second string

    t1->capacity = lengths;
    printf("%s \n", t1->content);
    printf("%d \n", t1->capacity);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...