Jadvalning bir qator elementiga string kiritilganda nima uchun quyidagi kod ko'rsatilgan chiqishni beradi?

#include 

int main(int argc, char *argv[])
{
    int i, n, m;

    scanf("%d %d", &n, &m);

    char s[m][n];

    for (i = 0; i < m; i++) {
        printf("the string --\n");
        scanf("%s", s[i]);
    }

    for (i = 0; i < m; i++) {
        printf("the strings are %s \n",s[i]);
        printf("\n");
    }

    return 0;
}

Chiqish quyidagicha:

2 2  
the string --
10  
the string -- 
11  

the strings are 1011 

the strings are 11

10 o'rniga birinchi string 1011 nima uchun?

0
char s [m] [n]; -> char s [m] [n + 1];
qo'shib qo'ydi muallif BLUEPIXY, manba
n o'lchamingiz 3 emas, balki 3 bo'lishi kerak. N-belgilar qatorini saqlab qo'yish uchun kamida N + 1 elementlari bo'lgan 0 qatoriga ega bo'lish kerak .
qo'shib qo'ydi muallif John Bode, manba
C- "string" do'koniga ega bo'lish uchun N-belgilar uni N + 1 o'lchamiga aylantiradi. 0 -terminator-ni eslang.
qo'shib qo'ydi muallif alk, manba

5 javoblar

In my opninion using scanf to read strings is just pure evil. That said the array s[m][n] is just s[m*n] of course. That said that evil thing scanf is going to load on *s[0] 10\n\0 and on *s[1*n] or *s[2] 11 and *s will be 1011\n\0

Va bu yomon C kodlash uchun yodgorlik. O'ylaymanki, bu faqat misol, lekin agar men bu savolni so'raganimda edi: "Hodiy, menga haqiqiy narsalar"

2
qo'shib qo'ydi

%s expects null terminated strings as an argument. When first string is read by scanf, there is not enough space for the null terminator within the allocated memory of first string. It will goes to the space next to the allocated space. Writing to unallocated space invokes undefined behavior.

% s identifikatori bilan kodlarni kiritish paytida printf null terminali '\ 0' topmaguncha, belgining belgilarini yozing. Bu erda 10 va 11 qatorlari bir-birining xotirasida saqlanadi, shuning uchun printf ikkinchi mag'lubiyatning bo'sh belgisini o'qiguncha birinchi qatorni yozadi .
Kirish n kodi sifatida 3 va siz natijalaringizni qabul qilasiz.

1
qo'shib qo'ydi
Nima uchun uning chiziqlari bekor bo'lmadi? scanf() null terminali parchalarni o'zgarmaydiganga yozadi.
qo'shib qo'ydi muallif Barmar, manba
U hali ham uni yozib olishga harakat qiladi, bu esa aniqlanmagan xatti-harakatlarga olib keladi.
qo'shib qo'ydi muallif Barmar, manba
Bu erda o'zgaruvchilar uchun '\ 0' uchun bo'sh joy yo'q. Birinchi satrdan keyin scanf '\ 0' yozing, lekin bu belgi ikkinchi mag'lubiyatning birinchi belgisi bilan yoziladi.
qo'shib qo'ydi muallif haccks, manba
@Barmar; Albatta, aniqlanmagan xatti-harakati.
qo'shib qo'ydi muallif haccks, manba

C da, satrlar null belgilar ( 0 yoki '\ 0' ) tomonidan bekor qilingan char qiymatlari ketma-ketligi sifatida ifodalanadi. Bu ikki belgilar majmuasini saqlash uchun uchta belgi uchun joy kerak: mag'lubiyatga oid tarkibning ikkita paydo bo'lishi, shuningdek null terminator belgisi.

Bu erda siz faqat har bir satrda ikkita belgi uchun etarli joy ajratgansiz, ammo uchta joy kerak.

Shunday qilib, s [0] qatoriga birinchi qatorni o'qiydi, lekin null terminator mos emas va shuning uchun ikkinchi qatorga s [1] . Endi s qatorlari qatori quyidagicha: {{'1', '0'}, {'\ 0', ...}} .

So'ngra, ikkinchi kodni s [1] qatoriga o'qiganida, yuqoridan toshgan null terminatorning ustidan yoziladi. Ikkinchi mag'lubiyat uchun null terminator o'z majmuasiga mos kelmaydi, shuning uchun u yana suyakka qaytariladi. Dastur bu erda qulab tushishi yoki boshqa ma'lumotlarni buzishi mumkin, chunki siz qator oxirigacha toshgansiz.

Endi s qatorlari sizning arizangiz shunday bo'ladi: {{'1', '0'}, {'1', '1'}} '\ 0' qatori tugagandan keyin bir joyda ko'rsatiladi.

printf birinchi satrni o'qishga ketayotganda, u null terminatorni topguniga qadar belgilarni yozib oladi. Ammo birinchi satrda topilmaydi, shuning uchun u davom etaveradi va ikkinchi qatorni uradi. U erda ham topilmaydi va qator oxirigacha davom etadi. Sizning holatingizda, noyob null terminator u erda edi, ammo barchamiz uchun boshqa narsa bo'lishi mumkinligini bilamiz.

Buni tuzatish uchun null terminator uchun 9 satrda mag'lubiyatga qo'shimcha belgi qo'yish kerak:

    char s[m][n+1];

Biroq bu erda yana bir muammo bor. Kirishingiz sizga noto'g'ri uzunlik beradi, nima bo'ladi? Misol uchun, agar sizning kirishingiz 2 3 deyilgan bo'lsa, ya'ni quyidagi satr 3 ta uzunlikka ega bo'ladi, ammo foobar kodini beradi, ya'ni 6 belgilar? Sizning kodingiz hozir bu mag'lubiyatni o'qigach tamponni to'ldiradi, chunki u to'g'ri uzunlik ekanligiga ishonch hosil qilmaydi.

Bunga yo'l qo'ymaslikning bir usuli quyidagicha bo'ladi: gets_s sscanf() o'rniga 13 qatoridagi satrlarni o'qish uchun ishlatiladi:

        gets_s(s[i], n+1);

Bu n belgilarining eng ko'p qismini o'qiydi, shuning uchun dasturingizni shikastlamaslik yoki xavfsizlik muammosini yaratish haqida o'ylang. Biroq, gets_s - bu C11 funktsiyasidir, shuning uchun siz uni ishlata olmaysiz.

1
qo'shib qo'ydi
Bu masala birinchi qismidir, O'X da har bir satr uchun faqat n nusxasini o'qish (yoki nusxa ko'chirish) kerak.
qo'shib qo'ydi muallif Bob__, manba
Xullas, siz kiritgan ma'lumotlarning noto'g'ri bo'lishi mumkin deb hisoblang. ;)
qo'shib qo'ydi muallif Bob__, manba
Yaxshi nuqta, men kirishni noto'g'ri deb hisoblamayman.
qo'shib qo'ydi muallif Andrea, manba
@Bob__ buni gets_s so'zini yangilab turdi
qo'shib qo'ydi muallif Andrea, manba

Har bir mag'lubiyatga 2 ta belgi, har bir mag'lubiyatga 4 ta belgi uchun 4 va hokazo kiritilganda ustun o'lchamini 3 ga o'rnatishingiz kerak. Buning sababi, C ning mag'lubiyati so'nggi holatda "kod" ("\ 0") ga ega.

0
qo'shib qo'ydi
     #include 

int main(int argc, char *argv[])
{
    int i, n, m;

    scanf("%d %d", &n, &m);

    char s[m][n+1];

    for (i = 0; i < m; i++) {
        printf("the string --\n");
        scanf("%s", s[i]);
    }

    for (i = 0; i < m; i++) {
        printf("the strings are %s \n",s[i]);
        printf("\n");
    }

    return 0;
}
0
qo'shib qo'ydi
bu kodni sinab ko'ring, bir string uzunligi n ni saqlashingiz kerak ... n soni raqamlar sonidan ko'p bo'ladi.
qo'shib qo'ydi muallif Shakil Mahmud, manba