如何让sscanf读到' \ 0'字符

时间:2018-05-20 21:09:35

标签: c scanf

我希望名称在justify-content: center;之前保留所有字符。

'\0'

我可以这样做:

#include <stdio.h>

int main(){
    char line[] = "1999-08-01,14.547,0.191,United Kingdom";
    unsigned int year, month, day;
    float temp, uncertainty;
    char name[100];
    sscanf(line, "%u - %u - %u, %f , %f , %s", &year, &month,
                       &day, &temp, &uncertainty, name);
    printf("%u-%u-%u,%lf,%lf,%s\n", year, month, day, temp, uncertainty, name);
}

但我发现这非常不优雅。

4 个答案:

答案 0 :(得分:3)

sscanf不是最优雅的界面,但它有很多功能。其中之一是能够找出你在输入字符串中的位置,这可以让你提取(或只是指向)“输入的其余部分”。

例如,之后;

int nchar = -1;
int nfield = sscanf(line, "%u - %u - %u, %f , %f , %n", &year, &month,
                    &day, &temp, &uncertainty, &nchar);

nchar将包含名称字段line中的偏移量(除非它仍为-1,表示sscanf与格式字符串不匹配)。如果该字段延伸到line的末尾,则可以直接使用它(line + nchar)或在检查它不是太长后将其复制到不同的字符串中。

如果line与其名称相反,包含多行,并且您希望将字符串提取到换行符,则可以使用两种%n格式,其间为%*[^\n] (这位明星压制副本,以避免出现超限问题):

char name[NAME_MAX + 1];
int nstart = -1, nend = -1;
int nfield = sscanf(line, "%u - %u - %u, %f , %f , %n%*[^\n]%n", &year, &month,
                    &day, &temp, &uncertainty, &nstart, &nend);
if (nend > 0) {
  if (nend - nstart <= NAME_MAX) {
    memcpy(name, line + nstart, nend - nstart);
    name[nend - nstart] = 0;
  }
  else {
    /* name is too long */
  }
}
else if (nstart > 0) {
  /* Name was 0 bytes long. Sscanf requires that %[ match at least
   * one character; if not, it fails the scan.
   */
  name[0] = 0; /* Perhaps you wanted to signal an error
}
else {
  /* Line didn't match format */
}

显然,我可以避免使用固定长度的缓冲区,并且当我知道它有多大时,需要通过动态分配缓冲区来检查溢出:

char* name = NULL;
// ...
if (nend > 0) 
  name = strndup(line + nstart, nend - nstart);

// or, if you don't like strndup
//   name = malloc(nend - nstart + 1);
//   memcpy(name, line + nstart);
//   name[nend - nstart] = 0;

如果你真正想要的是一个动态分配的字符串并且你有一个符合Posix的sscanf,你可以通过使用m长度修饰符来避免这种麻烦,这是一个全面的最简单的解决方案

char* name = NULL;
int nfield = sscanf(line, "%u - %u - %u, %f , %f , %m[^\n]", &year, &month,
                    &day, &temp, &uncertainty, &name);

有关详细信息,请参阅您的sscanf联机帮助页。在name被动态分配的所有情况下,不要忘记在完成它时释放()它。

答案 1 :(得分:2)

这应该有效:

char line[] = "1999-08-01,14.547,0.191,United Kingdom";
unsigned int year, month, day;
float temp, uncertainty;
char name[100];
sscanf(line, "%u - %u - %u, %f , %f , %99[^\n]", &year, &month,
                   &day, &temp, &uncertainty, name);
printf("%u-%u-%u,%lf,%lf,%s\n", year, month, day, temp, uncertainty, name);
找不到

'\n',但由于无法达到99的限制,sscanf将继续读取,直到字符串结束标记。

答案 2 :(得分:0)

几天前,我正在阅读书中的第2章&#34; Unix系统编程:通信,并发,线程&#34; ,2003年版本,我研究了一个例子,它导致使用自定义分隔符将字符串分解为标记(它可以是,或_或空格或其他)。它使用了strtok()C库函数。以下是调整示例以满足您的需求。我将提供2个文件:

makeargv.c

private View mView;
private EditText editText;

 @Override
        public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) {
            if (mView != null) {
                ViewGroup group = (ViewGroup) mView.getParent();
                if (group != null) {
                    group.removeView(mView);
                }
            } else {
                //Inflate layout for this fragment
                mView = layoutInflater.inflate(R.layout.frgament_layout, container, false);

                edittext = (TextView)(mView.findViewById(R.id.textViewVol));
                editText.setText("% Volumne");
            return mView;
        }

main.c

#include <errno.h>
#include <stdlib.h>
#include <string.h>

/* frees all the memory that was allocated by makeargv */
void freemakeargv(char **argv)
{
   if (argv == NULL)
      return;
   if (*argv != NULL)
      free(*argv);
   free(argv);
}
/* Now the function that breaks string s into tokens */ 
int makeargv(const char *s, const char *delimiters, char ***argvp) 
{
   int error;  int i;
   int numtokens;
   const char *snew;
   char *t;
   if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) 
    { errno = EINVAL; return -1; }
   *argvp = NULL; /* so that a failed call to malloc,will leave it NULL */
      /* now we consume any initial delimiters characters of input s */
   snew = s + strspn(s, delimiters);   /* snew is real start of string */
   if ((t = malloc(strlen(snew) + 1)) == NULL)
      return -1;
   strcpy(t, snew);
   numtokens = 0;
   if (strtok(t, delimiters) != NULL)  /* count number of tokens in s */
      for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ;
      /* next,create argument array for ptrs to the tokens */
   if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) 
    {
      error = errno;
      free(t);
      errno = error;
      return -1;
    }
      /* now insert pointers-to-tokens into the argument array */
   if (numtokens == 0)  free(t);
    else 
    {
      strcpy(t, snew);
      **argvp = strtok(t, delimiters);
      for (i = 1; i < numtokens; i++)
          *((*argvp) + i) = strtok(NULL, delimiters);
    }
    *((*argvp) + numtokens) = NULL;      /* append final NULL pointer */
    return numtokens;
}

gcc -Wall -std = c99 -o tokenizer main.c makeargv.c

并运行它

./ tokenizer

答案 3 :(得分:0)

@rici的好方法的变化:

  

如何让sscanf读到&#39; \ 0&#39;字符

使用>>> df a b c 0 0 1 2 1 3 4 5 2 6 7 8 3 9 10 11 4 12 13 14 5 15 16 17 >>> df1 a b c 0 0 1 2 1 3 4 5 2 6 7 8 >>> df.loc[0, 'a'] = 99 >>> df a b c 0 99 1 2 1 3 4 5 2 6 7 8 3 9 10 11 4 12 13 14 5 15 16 17 >>> df1 a b c 0 99 1 2 1 3 4 5 2 6 7 8 来处理&#34;线路的其余部分&#34; "%n"将扫描的偏移量记录到该点,如果它到达那么远 "%n"会进行扫描,但不会将所有角色保存到每个OP的%*[^\n]并保留在第34行

用它来分配结束字符串。

'\n'