c программа не выдаёт мне ошибок - PullRequest
2 голосов
/ 08 февраля 2020

Рассмотрим следующую программу

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


typedef struct my_string{
    int len;
    char *buf;
} my_string_t;


my_string_t *init_my_string(char *);
my_string_t *call_init_my_string();

int main(int argc, char *argv[])
{
     my_string_t *st1 = call_init_my_string();

     printf("%d\n", st1->len);
     printf("%s\n", st1->buf);

     free(st1);

    return 0;
}


my_string_t *call_init_my_string()
{
    my_string_t *st1 = init_my_string("Foo");
    return st1;
}


my_string_t *init_my_string(char *s)
{
    my_string_t *st = (my_string_t *) malloc(sizeof(*st));
    st->len = strlen(s);
    st->buf = s;
    return st;
}

Вопрос в том, предполагает ли эта программа неопределенное поведение или какую-то ошибку? поскольку строка "Foo" внутри функции call_init_my_string объявлена ​​локально и передана функции init_my_string. В функции init_my_string я выделяю пространство для хранения размера строки и самой строки, но, как я знаю, это распределение my_string_t *st = (my_string_t *) malloc(sizeof(*st)); выделяет достаточно места только для указателя st->len и st->buf, а не для строки "Foo", поскольку я только назначаю строку для st->buf вместо того, чтобы выделять ее сначала, а затем делаю следующее:

 st->buf = (char *) malloc(strlen(s) + 1);
 memcpy(st->buf, s, strlen(s));
 st->buf[strlen(s)] ='\0';

Но после того, как я скомпилирую и выполню, она не выдаст мне ошибок и программу работает нормально. почему эта программа работает нормально и не выдает никаких ошибок?

это результат, напечатанный на экране:

$ gcc struct_ptr_string1.c -o struct_ptr_string1
$ ./struct_ptr_string1

3
Foo

Ответы [ 2 ]

1 голос
/ 08 февраля 2020

В вашем коде нет неопределенного поведения.

Строковый литерал "Foo" имеет stati c длительность хранения . Вы передаете его адрес init_my_string и просто сохраняете этот адрес (по сути, указатель на "Foo").

Ваш код эквивалентен (за исключением того, что у нас есть еще одна копия "Foo"):

my_string_t *call_init_my_string()
{
    static char s[] = "Foo";
    my_string_t *st1 = init_my_string(&s[0]);
    return st1;
}

my_string_t *init_my_string(char *s)
{
    my_string_t *st = malloc(sizeof(*st));
    st->len = strlen(s);
    st->buf = s;
    return st;
}
1 голос
/ 08 февраля 2020

Строка "Foo" является константной строкой, которая, вероятно, хранится где-то статически. В init_my_string происходит то, что вы действительно выделяете новый фрагмент памяти, но вы назначаете st->buf на s, который является указателем, указывающим на эту строку «Foo». Таким образом, вы не копируете «Foo», а просто устанавливаете st->buf в место, где оно хранится.

my_string_t *init_my_string(char *s)
{
    my_string_t *st = (my_string_t *) malloc(sizeof(*st));
    printf("st address=%d\n", st);
    printf("s address=%d\n", s);
    st->len = strlen(s);
    st->buf = s;
    printf("st->buf address=%d\n", st->buf);
    return st;
}

Вывод:

st address=19779600                                                                                                                                                                
s address=4196344                                                                                                                                                                  
st->buf address=4196344                                                                                                                                                            
3                                                                                                                                                                                  
Foo  

Как вы видите st->buf на самом деле указывает на постоянную строку, поэтому без ошибок.

...