C 对于VAU列表中的循环过程,继续漫无目的地使用(?)K&;R

C 对于VAU列表中的循环过程,继续漫无目的地使用(?)K&;R,c,pointers,for-loop,continue,kernighan-and-ritchie,C,Pointers,For Loop,Continue,Kernighan And Ritchie,下午好!我对下面的代码有一些疑问 [1] for循环中的中间条件意味着什么*p和*斯瓦尔-到达输入字符串的末尾?如果是,如何确定 [2] 我不明白那个复杂的for循环 假设条件不满足,*p==%,那么我们马上进入开关。现在让我们考虑相反的情况,我们进入每个其他字符,尽管代码> %>代码>,如果满足,那么我们使用Salk,然后再转到代码>开关< /代码>。那么这两种情况有什么区别呢? 我一定是做错了什么,但我已经两个多小时找不到我的错误了 #include <stdarg.h> /*

下午好!我对下面的代码有一些疑问

[1] for循环中的中间条件意味着什么<代码>*p
*斯瓦尔-到达输入字符串的末尾?如果是,如何确定

[2] 我不明白那个复杂的for循环

假设条件不满足,
*p==%
,那么我们马上进入开关。现在让我们考虑相反的情况,我们进入每个其他字符,尽管代码> %>代码>,如果满足,那么我们使用Salk,然后再转到代码>开关< /代码>。那么这两种情况有什么区别呢? 我一定是做错了什么,但我已经两个多小时找不到我的错误了

#include <stdarg.h>
/* minprintf: minimal printf with variable argument list */
void minprintf(char *fmt, ...)
{
    va_list ap; /* points to each unnamed arg in turn */
    char *p, *sval;
    int ival;
    double dval;

    va_start(ap, fmt); /* make ap point to 1st unnamed arg */

    for (p = fmt; *p; p++) {         /* [1] */
        if (*p != '%') {
            putchar(*p);
            continue;                /* [2] */
        }
        switch (*++p) {
        case 'd':
            ival = va_arg(ap, int);
            printf("%d", ival);
            break;
        case 'f':
            dval = va_arg(ap, double);
            printf("%f", dval);
            break;
        case 's':
            for (sval = va_arg(ap, char *); *sval; sval++)
                putchar(*sval);
            break;
        default:
            putchar(*p);
            break;
        }
    }
    va_end(ap); /* clean up when done */
}
#包括
/*minprintf:具有变量参数列表的最小printf*/
void minprintf(字符*fmt,…)
{
va_列表ap;/*依次指向每个未命名的参数*/
char*p,*sval;
国际竞争力;
双dval;
va_开始(ap,fmt);/*使ap指向第一个未命名参数*/
对于(p=fmt;*p;p++){/*[1]*/
如果(*p!=“%”){
putchar(*p);
继续;/*[2]*/
}
开关(*++p){
案例“d”:
ival=va_arg(ap,int);
printf(“%d”,ival);
打破
案例“f”:
dval=va_arg(ap,双精度);
printf(“%f”,dval);
打破
案例s:
for(sval=va_arg(ap,char*);*sval;sval++)
putchar(*sval);
打破
违约:
putchar(*p);
打破
}
}
va_end(ap);/*完成后进行清理*/
}

非常感谢您的帮助

当我们
继续
时,我们只需打印字符,并完全跳过切换。循环通过格式行查找(1)终止零或(2)百分号

当达到终止零点时,循环结束:

for (p = fmt; *p; p++)
//            ^^^ Here is the condition: *p != 0 is implied
当达到百分号时,将以下符号作为格式字符,并根据它解释下一个vararg


此程序中存在一个错误-当百分比符号是格式字符串的最后一个字符时,它会产生超过格式字符串末尾的读取(未定义的行为)。试试这个:

minprintf("%\0bug!bug!bug!");
模拟的行尾标记
\0
被跳过,并且
错误!缺陷臭虫输出。原因是
开关
语句的头中有一个无条件的
p
前置增量。要解决此问题,请将以下情况添加到
开关中:

 case '\0':
    p--; // reverse the ++p from the header of the switch
    break;

*p*sval—指向字符串中字符的取消引用指针。 在C语言中,字符串以“\0”符号结尾。 所以如果我们从p,sval点得到的值为零,我们显然已经到达了字符串的末尾

2 in-loop continue用于跳过它后面的所有语句,并返回到循环头,同时执行(;;语句)

  • [1] 是继续循环,直到它没有得到字符串的null终止字符
    '\0'
  • [2] 如果字符不是
    '%'
    ,则为打印字符。如果字符串中的
    '%'
    下一个字符标识如何从列表中打印下一个
    va_arg

谢谢。我有一个关于那个bug的问题。为什么跳过\0,它跳过哪一行?至于我,你所描述的意外%\0和行为不是错误。它只是省略了\0并在它后面打印单词。如果%\0位于字符串的末尾,则不会出现printf,它将正确结束。我说得对吗?@PeterKowalski当你传递一个以
%
结尾的字符串时,例如
“Hello%”
miniprintf
将读取字符串的结尾,这是禁止的。我在字符串字符串的中间放置了一个终止零点,以说明一个超出空终止的读将发生的点。程序不一定总是崩溃并不重要:未定义的行为可能导致意外后果,必须始终避免。好的。现在我明白了。然而,它不应该是--p而不是后减量吗?@PeterKowalski看一看另一个例子,当一个字符串以
%
@PeterKowalski Pre increment或post increment结尾时,在不使用increment/assign表达式的值的情况下,打印不需要的垃圾并不重要;你可以用任何一个。