1 Востаннє редагувалося М18х00 (19.12.2017 02:05:53)

Тема: Як розрізняти функції різні різновиди char-ів?

Будь ласка підкажіть!

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


#include<cassert>


 char *__cdecl strcat(char *A0, const char *A1)
{
    /* int hru = 0;
    printf("Vvedit: \n");
    scanf ("%d", &hru);
    assert(hru+2==4);
    printf ("Execution continues past the first assert\n");
    assert(hru+2==5);
    printf ("Execution continues past the second assert\n"); */
    assert (!(A0== NULL) && !(A1== NULL));
    char *tmp = A0;
    while (*A0)*A0++;
    while (*A1)*A0++=*A1++;
    *A0 = 0;
    return tmp;
}









char *__cdecl strcpy(char *A0, const char *A1)
{
    char *temp = A0;
      size_t min_size = (strlen(A0) < strlen(A1)) ? strlen(A0) : strlen(A1);

//while( *A0 && *A1 ) *A0++ = *A1++;
while( *A1 ) *A0++ = *A1++;
*A0 = 0;
return temp;


}



int main()
{

  char str1[40];
  char str2[40];

  char str[100];
  char Tsi[] = "Tsi ";
  char rjadky[] = "rjadky ";
  char obednany[] = "obednany ";
  char operatsieju[] = "operatsieju ";
  char konkatenatsiji[] = "konkatenatsiji.";

  char newchar400_ = new char[400];
  assert (!(newchar400_== NULL));

  strcpy ( newchar400_ , Tsi );
  strcpy ( str, Tsi );

  strcat ( newchar400_, rjadky);
  strcat ( newchar400_, obednany);
  strcat ( newchar400_, operatsieju);
  strcat ( newchar400_, konkatenatsiji);


  strcat ( str, rjadky);
  strcat ( str, obednany);
  strcat ( str, operatsieju);
  strcat ( str, konkatenatsiji);

  printf ("Trymaj (%s)\n", str);


  strcpy (str1,"ABCD ");
  strcpy (str2,"EFGHJYU");

  //strncat (str1, str2, 2);    //

    printf ("Trymaj (%s)\n", str1);
    char *O = "QWERTYUIOOOOPASDFGHJKL";
    //char *B = char temp[500];
    char *B = "0000000000000000000000000000000000000000000000000000000000000000000000000";
    //memset(B,0,500);
    strcpy(B,O);
    printf ("Trymaj (%s)\n", B);
 return 0;
}
 

Ghbgecnbvj припустимо я розмірковую над функцією.  От що виходить, що мені потрібно розрізняти
що це за char, бо ж виходить що це зовсім різна справа. Це зовсім різна справа, чі то char *O, леть знамагавсь його змінити а тут сегментація!  Або це char str2[ щось ] ,  або new char[ щось ];
все це зовсім різна справа. От чі можна якось розрізняти їх у функції?  Бо інакще вона буде якась недороблена, з цім треба хоч щось якось робити.

До речі, код падає, але питання не в цьому.

Post's attachments

pomylka1.bmp 2.25 mb, 488 downloads since 2017-12-18 

2 Востаннє редагувалося koala (19.12.2017 11:27:56)

Re: Як розрізняти функції різні різновиди char-ів?

Немає різниці - і те, і те є вказівником. Так, char str[] не може бути нулем; але функція не може визначити, який саме вказівник їй передали -на статичну змінну чи на динамічну (насправді може, але це потребує детального розбору роботи компілятора і середовища виконання).
А от так:

    char *O = "QWERTYUIOOOOPASDFGHJKL";
    char *B = "0000000000000000000000000000000000000000000000000000000000000000000000000";
    strcpy(B,O);

робити не можна. Справа в тому, що рядкові літерали розташовуються сучасними компіляторами в області пам'яті тільки для читання; за рахунок цього можна об'єднати кілька однакових літералів в один.

char *a = "Hello!";
char *b = "Hello!";
assert(a==b);//компілятор має право об'єднати обидва літерали, і це спрацює

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

const char *O = "QWERTYUIOOOOPASDFGHJKL";

І, гадаю, ще компілятор видає купу попереджень на цьому коді; раджу не ігнорувати їх, попередження пишуться не просто так.
Потім бачу

char newchar400_//може char*?

І, будь ласка, якщо вивчаєте C (а printf і char* вказують якраз на це), то і працюйте з C, а не з C++. Не <cassert>, а <assert.h>; не new, а malloc чи calloc і т.д. І файл назвіть .c, щоб компілятор не помилився.

Подякували: cheappi386, leofun01, М18х003

3 Востаннє редагувалося М18х00 (24.12.2017 19:49:21)

Re: Як розрізняти функції різні різновиди char-ів?

Надзвичайно дякую! 

Так, char str[] не може бути нулем;   ---Так, здається я й не подумав! Правда, наче прозріння.


але функція не може визначити, який саме вказівник їй передали -на статичну змінну чи на динамічну (насправді може, але це потребує детального розбору роботи компілятора і середовища виконання).                                  ---От печалька! Така журба.  Якщо памьять діниамична, то треба б діяти  по-одному, тобто виділити достатньо памьяти під нову строку.  Якщо це  char str[] (а до речі яка це памьять? Статична? щось не зміркую) так тоді той варіант що в мене досить годний і гарний. Не розрізняти неможна.  А ще хотілося б при помилках з функції годні ассерти посилати.



char newchar400_//може char*?         ----Дякую! Так, помилка зникає; а assert (!(newchar400_== NULL))   прогавив її в повний зріст! 


const char *O       ----Так, так і буду робити, так й самому ясніше.   До речі, при спробі хоч якось змінювати ці рядки, прога одразу ж валться з сегфолтом.


І, будь ласка, якщо вивчаєте C (а printf і char* вказують якраз на це), то і працюйте з C, а не з C++. Не <cassert>, а <assert.h>; не new, а malloc чи calloc і т.д. І файл назвіть .c, щоб компілятор не помилився.                  ----Та ні, це скоріше C++, хоча може й вийшов якийсь гибрид... Але я з вами, прошу вибачення таки не згоден,  прога з printf виконується 0.009 секунди, уявляєте прога наповнена двома-трьома виведеннями std::  і відповідно хоч одним введенням, виконується вже щонайменше 0,047 секунди, і чого б для простого введення-виведення не використовувати printf!

А то що стосується цього __cdecl, так я пишу його тому що всі чомусь пишуть,  не надто вдаючись у сутність значення, щоб красивіше виглядало.

4 Востаннє редагувалося koala (24.12.2017 20:21:29)

Re: Як розрізняти функції різні різновиди char-ів?

Користуйтеся тегами qoute (лапки на панельці інструментів), будь ласка.

---От печалька! Така журба.  Якщо памьять діниамична, то треба б діяти  по-одному, тобто виділити достатньо памьяти під нову строку.  Якщо це  char str[] (а до речі яка це памьять? Статична? щось не зміркую) так тоді той варіант що в мене досить годний і гарний. Не розрізняти неможна.  А ще хотілося б при помилках з функції годні ассерти посилати.

Це буде дуже некрасивий спосіб - іноді виділяти пам'ять, а іноді - ні. Той. хто буде використовувати вашу функцію, не знатиме, чи треба йому вивільнювати пам'ять. Для цього в C++ і використовують класи і RAII.
char str[] - залежно від того, в функції чи поза нею, стековий чи статичний. Ну, ще можна static дописати, тоді точно статичний.

Прихований текст

До речі, Rust вміє розрізняти тип пам'яті на рівні компілятора. Точніше - будь-яка функція в Rust є, насправді, шаблоном функції, який інстанціюється залежно від переданих параметрів окремо для статики, стеку і динаміки (трохи прибрехав, якщо чесно). Але яка різниця програмісту? Все одно пишеться одна функція

Дякую! Так, помилка зникає; а assert (!(newchar400_== NULL))   прогавив її в повний зріст!

Нічого він не прогавив. Це ви програвили попередження, що в char буде внесений вказівник (і більша частина його, відповідно, втратиться). А assert чесно порівняв char newchar400_ зі значенням NULL, і оскільки з імовірністю 255/256 char був не 0, сказав, що все гаразд.

----Та ні, це скоріше C++, хоча може й вийшов якийсь гибрид... Але я з вами, прошу вибачення таки не згоден,  прога з printf виконується 0.009 секунди, уявляєте прога наповнена двома-трьома виведеннями std::  і відповідно хоч одним введенням, виконується вже щонайменше 0,047 секунди, і чого б для простого введення-виведення не використовувати printf!

Насправді вони працюють з однаковою швидкістю, якщо ніхто з них не перевіряє стан буферу виведення одне одного.  Але оскільки багато людей плутає, з якою системою виведення вони працюють, система iostream типово перевіряє, чи не виводить щось зараз система stdio, і через це гальмує. Додайте
std::ios::sync_with_stdio(false);
на початок програми і переконайтеся, що там ті самі 0,009 секунд. Зате одночасна робота з printf стає ускладненою.

А то що стосується цього __cdecl, так я пишу його тому що всі чомусь пишуть,  не надто вдаючись у сутність значення, щоб красивіше виглядало.

__cdecl - це угода про виклики. Якщо ви не знаєте, що це, і не пишете dll чи якийсь інший експортний код, краще їх не уточнювати.

Подякували: sensei, leofun012