LINUX.ORG.RU

Лишние символы в конце строки - C

 , , ,


0

1

Я выполняю операции декодирования, записываю всё это в массив длиной 5000, и конвертирую его в понятный для программы формат. В большистве случаев строка отображается нормально, но в некоторых выдаёт такое: «SourceX\x06». В норме выдаёт «Source».

Это мой код:

char string[5000] = {‘S’,‘o’,‘u’,‘r’,‘c’,‘e’,‘\0’};

char *out = malloc(strlen(string) + 1);

strcpy(out, string);

return out;

Помогите, я не знаю в чём дело, пробовал уменьшать длину массива до 6, убирал при этом +1, но не помогло, в конце опять этот бред.



Последнее исправление: gradle (всего исправлений: 2)

Я ничего не помню, но это нормально, что string - массив char, а out - указатель на char? То есть нормально ли при этом отрабатывает strcpy?

grem ★★★★★
()
Ответ на: комментарий от Deleted

Вот код где выводится строка gl_rendrer, дальше уже найти не могу.

static char *dup() { char string[5000] = {‘S’,‘o’,‘u’,‘r’,‘c’,‘e’,‘\0’};

char *out = malloc(strlen(string) + 1);

strcpy(out, string);

out[strlen(string)] = ‘\0’;

return out; }

static const char *get_vendor(struct pipe_screen *screen) { return dup(); }

static const char *get_name(struct pipe_screen *screen) { static char buf[100];

snprintf(buf, sizeof(buf), «%s %u.%u, %u %s», dup(),

        8, 0,

        128,

        dup());

return buf; }

gradle
() автор топика
Ответ на: комментарий от crutch_master

strcpy всё равно на эти нули в конце. Он просто копирует до первого встречного нуля и ставит нуль в dst. Всё, не больше, не меньше.

А гредл просто тупой как одноименная билдсистема.

a1batross ★★★★★
()
Ответ на: комментарий от Deleted

Он копирует string в out. В out - мусор. Копирует по длине string, которая = 7

string : 'lalala0'
out : 'xxxxxxxxxxxxxxx'
после strcpy получается
out : 'lalala0xxxxxxxx'
Предполагаю, что его конвертор съедает '0x' и получается говно.

crutch_master ★★★★★
()
Ответ на: комментарий от crutch_master

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

gradle
() автор топика
Ответ на: комментарий от gradle

gl_rendrerer выводится в glxinfo нормально, а в wined3d в логах с лишними буквами в конце. gl_vendor проверить не могу, он нигде там не выводится

gradle
() автор топика
Ответ на: комментарий от gradle

если это «отвратительный язык» (на самом деле, просто кое-кто типичный неосилятор), то не лезь, нафиг, в чужую библиотеку. ладно бы ещё школоподелие было, в учебных целях. но чтобы править чужие библиотеки надо, как минимум, понимать, что делаешь. а ты не понимаешь. вот нравится тебе жабка - иди в эту песочницу и там ковыряйся. не лезь в серьёзный код.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от gradle

Wined3d:

(using GL_RENDERER «Source 8.0, 128 SourceX\x06»).

glxinfo:

OpenGL renderer string: Source 8.0, 128 Source

gradle
() автор топика
Ответ на: комментарий от grem

Да, это нормально. string одновременно массив и указатель так сказать...

Deleted
()
Ответ на: комментарий от gradle

баг проявляется только в проприетарной программе в wine

Ну то есть косяк почти однозначно сделан ЗА ПРЕДЕЛАМИ изначально приведённого куска кода, как тебе три человека почти сразу и сказали.

Кто-то что-то не туда пишет. А последствия косяка могут проявляться, а могут и не проявляться. Закомментировал одну строку (ни в чём не виноватую) — память сдвинулась, и ошибка перестала быть фатальной.

Я бы порекомендовал погонять программу под valgrind, но если у тебя wine, а под ним ещё и нечто без исходников — то не знаю.

hobbit ★★★★★
()
Ответ на: комментарий от gradle

А зачем все эти танцы с бубном вокруг копирования если тебе просто надо вывести строку?

static const char* dup() { 
    return "Source"; 
}

static const char *get_vendor(struct pipe_screen *screen) {
    return dup(); 
}

static const char *get_name(struct pipe_screen *screen) { 
    static char buf[100];
    snprintf(buf, sizeof(buf), «%s %u.%u, %u %s», dup(), 8, 0, 128, dup());
    return buf; 
}

dyb4hzvo
()
Ответ на: комментарий от dyb4hzvo

Source это заглушка, там должна строка генерироваться.

Deleted
()
Ответ на: комментарий от gradle

Щас я удалил на время декодер, чтобы подозрений на него не было.

gradle
() автор топика
Ответ на: комментарий от gradle

При том что если я просто возвращаю «Source» без strdup/strcpy, такой проблемы нет.

gradle
() автор топика
Ответ на: комментарий от gradle

У тебя в dup() динамически память выделяется и нигде не освобождается.

Проверь кодировку исходника. Может ты копипастом вставил невидимые юникод символы в исходник? В твоём сообщении кавычки странные. Перепиши руками.

На глаз никаких проблем. Ещё можешь проверить код возврата функции snprintf должен быть больше нуля и содержать количество записанных байт.

ox55ff ★★★★★
()
//тут после символов лежит мусор, не забывай
char string[5000] = {‘S’,‘o’,‘u’,‘r’,‘c’,‘e’,‘\0’};


char *out = malloc(strlen(string) + 1);
memset(out,'\0',strlen(string)+1);// заполни весь кусок нулями потом копируй
strcpy(out, string);

Для выделения можно использовать calloc() он инициализирует выделенную память нулями, но без гарантий.

Ради скорости порой можно не очищать буферы памяти, но только тогда когда ты точно знаешь что делаешь. В случае неопределённости, разная используемая длинна и тому подобное любую память, от malloc/calloc после получения заполняй одним значением, в случае букавок заполняй нулями дабы получать везде где данные не используются конец строки. В случае неожиданностей (ты напутал индексы или ещё что) ты можешь ради теста заполнить данные например символом ‘A’ и выявить то где ты не прав и на косячил.

Помни в си ты оперируешь просто блоками памяти.

1 - Получил/зарезервировал память, сохранил размер памяти

2 - Заполнил(очистил) память определённым значением

3 - Можно использовать память при этом всегда контролируй размер обращения к ней

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от gradle

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

beastie ★★★★★
()

Именно в куске начала треда ошибок нету. Совсем. Этот код должен работать правильно. Что то происходит в другом месте, запускай анализаторы, смотри что происходит с твоими данными итд. Можешь попробовать собирать либу без оптимизаций.

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

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от gradle

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

grem ★★★★★
()
Ответ на: комментарий от gradle

Это мусор, ты читаешь больше данных чем хочешь прочесть, не проставлен \0 в конце данных для функций работающих с символами или ты явно читаешь по идексу который больше чем нужен. Но раз ты говоришь что у тебя ошибок нет и точка то про что разговор? Значит баг компилятора/процессора… Ой ли? Ищи свою ошибку усерднее.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от gradle

Вот код где выводится строка gl_rendrer, дальше уже найти не могу.

И никто не найдёт, с таким форматированием-то. Я полминуты пялился в твой snprintf, пытаясь понять, где у него последний аргумент и закрывающаяся скобка. Потом сообразил, что его кусок ушёл в спойлер. Где начинаются и заканчиваются функции? Почему определение переменной в той же строке, что и начало фукции?

Тебе уже писали — оформляй код как положено. Если у тебя форматирование через лоркод, заключай его в [code], если маркдаун — в пару из трёх апострофов.

hobbit ★★★★★
()
Ответ на: комментарий от SR_team
dmitry@msi:~$ gcc main.c -Ofast -march=native -Wall
dmitry@msi:~$ for i in {0..1000}; do ./a.out; done
dmitry@msi:~$ :)^C
dmitry@msi:~$
Deleted
()
Ответ на: комментарий от LINUX-ORG-RU

Подскажи хотя бы, как вывести в printf строку с мусором? Она в моей тестовой программе выводится без мусора, в glxinfo тоже, а в wined3d с мусором. В норме wined3d выводит нормальную строку, если я ничего не преобразовывал.

Мне надо повторить такую же ситуацию как в wined3d в моём printf, иначе нет смысла что-то искать, когда библиотека компилится 10 минут.

gradle
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

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

gradle
() автор топика
Ответ на: комментарий от gradle

Странно

А у меня доступен, даже под анонимусом:

int main()
{
    return 0;
}

Видишь, при добавлении комментария над редактором комментария есть комбмбокс «Разметка»? Вот в нём выбираешь один из вариантов, под комментарием есть ссылки на инструкции по их применению.

// Разлогинившийся hobbit

P.S. Запомните, твари --- Я НЕ РОБОТ!!! (ТС, это не тебе, если что...)

anonymous
()
Ответ на: комментарий от LINUX-ORG-RU
memset(out,'\0',strlen(string)+1);// заполни весь кусок нулями потом копируй
strcpy...

Не надо с умным видом генерить длинный бред. Не нужен тут memset, о чём тут в треде уже даже проговорено.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от gradle
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char *dup() 
{ 
    // Я подозреваю это не актуальный код, если актуальный то можно просто 
    // return "Source"; и всё
    char string[5000] = {'S','o','u','r','c','e','\0'}; // эта строка кода прямо так и существует? Если да то ничего кроме return "Source"; не надо
    char *out = malloc(strlen(string)+1); //ок
    memset(out,'\0',strlen(string)+1);// давай всё же зачистим 
    strcpy(out, string);//ок
    //out[strlen(string)] = '\0'; // ненужно мы полностью зачистили выше
    return out; 
}

// ок, разделяй и властвуй тут всё хорошо
// но если вверху возвращается всегда "Source" то ты прямо тут можешь вписать
// return "Source";
static const char *get_vendor(/*удалил для себя*/)
{ 
    return dup();
}

static const char *get_name(/*удалил для себя*/)
{ 
    static char buf[100]; // этот буфер содержит мусор
    memset(buf,'\0',100); // давай заполним его ^.^ он будет чистенький листочек

    //а теперь давай запишем на чистенький листочек нашу строчку
    snprintf(buf, sizeof(buf), "%s %u.%u, %u %s", dup(),8, 0,128,dup());
    // и вернём чистый листочек с аккуратной строчкой
    return buf; 
}


int main(int argc, char *argv[])
{
    //Пробуем!
    

    //Зеркал зеркалко скажи и Габену подскажи чей движочек всех милее
    //чьи модельки красивее, шейдера на всём летают анимашки не лагают
    //Назовика ты дружок лучший в мире мне движок!
    
    printf("[Молвит зеркальце в ответ  ] Лучше '%s' двига нет!\n",dup());

    //Солнце зеркальце, родная что-тоя глухонемая, молви слово снова мне
    //кто рендерит как во сне!
    
    printf("[Молвит зеркальце тут снова] '%s' ЛУЧШЕ  СНОВ ЛЮБОГО!\n",get_vendor());

    //Чистый свет мой зеркалёк, голос твой настоль высок что от радости я вся
    //прям не знаю зя-зя-зя. Ты скажи скорее мне полно имя поскорей!
    
    printf("[Снова зеркальце глаголит  ] Полно имя таковое, '%s'!\n",get_name());


    return 0;
}

dron@gnu:~$ gcc mmm.c -O0
dron@gnu:~$ ./a.out 
[Молвит зеркальце в ответ  ] Лучше 'Source' двига нет!
[Молвит зеркальце тут снова] 'Source' ЛУЧШЕ  СНОВ ЛЮБОГО!
[Снова зеркальце глаголит  ] Полно имя таковое, 'Source 8.0, 128 Source'!
dron@gnu:~$ 

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от vodz

Не надо с умным видом генерить длинный бред.

Не надо с умным видом пологать что ТС делает всё именно так как говорит, сейчас он сделает запись в буфер строки размером в половину буфера и там не будет на конце ‘\0’ и снова траблы.

Если есть буфер памяти и ты хочешь с ним работать не надо самому себе палки в колёса совать и буфер надо заполнить. Это сейчас в сею секунду ты уверен как ты с ним работаешь, но прошла неделя буфер остался где то выше по коду, а ниже ты решил сделать финт загзагом и заполнять его по иному, не до конца, частично, местами, поблочно, еtc и вдруг появился мусор, надо идти смотреть где косяк. Новичкам особо сложно, они постоянно забывают контролировать память и у них часто вылетает мусор и они не понимают откуда. Явное заполнение памяти инициализатором даёт чёткую и однозначную гарантию что всё правильно, а если где то ошибка то уже по одному значению инициализатора можно понять где ошибка.

Я говорю не с умным видом, а с синяками. Очищать надо, всегда и всё по возможности чтобы потом не «Ой а mingw под wine делает не совсем так как gcc под linux! Вот внезапность!»

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

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

Deleted
()
Ответ на: комментарий от Deleted

Если ты не можешь контролить то где поставить ноль

wine

Привет

 len = vsnprintf(NULL,0,fmt,args);
 ...
 buff[len+1]='\0';

Который в linux gcc вернёт размер построенной строки из аргумертов, а в wine mingw, mingw cross на linux или SDL_vsnprinf() вернёт нуль. Вот и кек, лол. Как так и куда копать. Новичок на подобном просто сломается. Это только один пример, подобного тонна.

Я выше написал если всё однозначно то не надо ничего занулять, но если есть непонятки и уж тем более где-то явно вылез мусор, то занули и глянь явно где косяк. Никакие gdb не впёрлись залил в буфер явно и всё сразу видно. А если не видно то сразу понятно что дело в чём то другом.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от Deleted

Конечный, конечно. Я же многоточие проставил опустив проверки, ну хорошо вот тогда так,выясняем какой размер нам нужен, выделяем, заполняем и впиндюриваем конец строки, но суть то одна.

int len = 0;
char *  buffer = malloc(sizeof(char) * (len = vsnprintf(NULL,0,fmt,args)+1)  );
vsnprintf(buffer,len,fmt,args);
buffer[len]='\0';

Конечно и тут проверки нужны, но всё же.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

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

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Я к тому что зануление лишь маскировка проблемы

Салютую, да.

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

Да, пусть падает, но когда я вижу в выхлопе «!!!!!+asdf/as+df/5» я хоть догадаюсь где у меня буфер заполненный ! я во про это.

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

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Частично помогло, только в memset я удалил +1 на всякий случай (в dup), get_name оставил как у тебя было.

Теперь наоборот:

wined3d:

(using GL_RENDERER «Source 8.0, 128 Source»)

glxinfo:

OpenGL renderer string: Source 8.0, 128 SourceX

Что за икс появился понятия не имею, зато в wined3d он исчез.

gradle
() автор топика
Ответ на: комментарий от Deleted

Мы про ТС говорим, он ничего трассировать и отлаживать не будет.

Опять же, отстань я эстет и свои буфера держ чистыми! А твои буфра чистые? :D Всё, я чай пить пошёл с печеньками, тут уже скучно.

К слову. Помнишь я демку обещал? Уведомляю техно демка будет в виде крайтековской sponza https://www.youtube.com/watch?v=14rV1JkpC2M как основы ^.^ Там и освещение удобно бенчить, проверять и физику и анимации и партиклы и прочее.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Я говорю не с умным видом, а с синяками.

Дык, опять понаписали длинный бред. Если я хочу, чтобы строка скопировалась, то я и пишу strcpy, если я хочу сформировать строку по формату, то sprintf. Не появиться нулю на конце да еще «а завтра» равнозначно высказыванию, что давайте на каждом шаге проверять, а не сбойнула ли ячейка памяти от пролетевшего мимо нейтрона и стало 2+2=5. Так вам понятнее? Я честно старался вам подражать.

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.