2010-10-16 3 views
2

Прошло некоторое время с тех пор, как я посмотрел на C (все еще учился), и я только что вернулся в книгу K & R.Является ли K & R обучением плохой читаемости?

Я только что пошел Упражнение 5-3 (p107).

Напишите указатель версии функции strcat, который мы показали в главе 2: strcat (s, t) копирует строку t в конец s.

Я придумал this ...

void strcat(char *s, char *t); 

void strcat(char *s, char *t) { 

    while (*s++ != '\0'); 
    s--; 
    while (*t != '\0') { 
     *s++ = *t++; 
    } 

    *--t = '\0'; 

} 

int main() { 
    char str[] = "Hey, hello"; 
    char str2[] = " are you?"; 

    strcat(str, str2); 

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

    return 0; 

} 

Это похоже на работу.

Что мне интересно, так это то, что книга K & R часто пишет упражнения с минимальными строками - я бы ожидал, если бы они предоставили свой собственный пример кода выше, вы бы получили такие вещи, как this ...

void strcat(char *s, char *t) { 

    while (*s++ != '\0'); 
    s--; 
    while ((*s++ = *t++) != '\0'); 
    *--t = '\0'; 

} 

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

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

Это только The C Way?

+6

Книга K & R была написана как 25 лет назад (32, если быть точным). Вещи переместились на ... –

+1

Если вам когда-либо приходилось писать программы, используя телетайп или перфокарты, то вы бы оценили терпение - в эти дни, конечно, гораздо важнее стремиться к ясности, а не к лаконичности. –

+0

C был одним из первых языков, которые я узнал. НО, зачем учиться C? Вам лучше учиться C# –

ответ

13

K & R объяснить важность идиом в книге. Да, краткость кода ценится программистами С, но это не намеренно кратковременно наказывать новичков. После некоторого времени чтения и письма C вы начинаете распознавать шаблоны, поэтому, когда вы видите их в чужом коде, вы знаете, на что вы смотрите.

Пройдите через итерации strcpy(), приведенные в качестве примера в K & R - они объясняют свою философию краткости и ясности и говорят об идиомах.

5

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

Вы определяете два буфера определенного размера (str имеет длину 11 байт, str2 - 10 байт в длину). Затем, в течение strcat, вы пытаетесь написать str[11], которого не существует. С этого момента нет никакой гарантии о выполнении вашей программы. Он может упасть, он может сделать то, что вы ожидали, или просто напечатать «42» и заставить вас задаться вопросом, почему.

Кроме того, вы не должны изменять *t в strcat, так как в новых версиях C t имеет тип const char *.

И, в-третьих, при повторной реализации функции, которая также предоставляется вашей средой, дайте ей другое имя. В противном случае ваш компилятор может заменить его некоторым встроенным кодом, который эквивалентен вызову функции. Например, GCC имеет __builtin_strlen, который иногда заменяет вызовы на strlen.

Фиксированный версия кода выглядит следующим образом:

#include <stdio.h> 

/* renamed strcat to str_cat to avoid confusing the compiler */ 
void str_cat(char *s, const char *t) { /* added the const qualifier to t */ 

    while (*s++ != '\0'); 
    s--; 
    while (*t != '\0') { 
     *s++ = *t++; 
    } 
    /* removed the needless modification of *t */ 
    *s = '\0'; /* edit: added this line after the comment from Jonathan Leffler */ 
} 

int main() { 
    char str[80] = "Hey, hello"; /* note the large array size here */ 
    char str2[] = " are you?"; 

    str_cat(str, str2); 
    printf("%s\n", str); 

    return 0; 

} 
+0

+1 благодарит за эту полезную информацию! – alex

+0

Вы правы, что '* - t = '\ 0';' не должны содержать декремент; но вам нужно обнулить строку с '* t = '\ 0';' потому что цикл не копирует NUL. –

+1

Возможно, код должен был быть '* s = '\ 0''. Я до сих пор не вижу причины изменять что-либо, связанное с 't'. Когда вызывается 'strcat',' t', как предполагается, указывает на строку, которая (по определению) включает в себя, что она завершена NUL. –

0

Other more readable, more efficient examples можно найти с помощью Google Codesearch.

Посмотрите на исходный код для Android и BSD, в частности, в качестве хороших примеров более современной реализации C strcat.

Вместо strcat вы должны написать описание strlcat и many examples этого источника.

Смежные вопросы