如何从C

时间:2018-05-20 00:22:06

标签: c arrays file struct scanf

我试图从文件中读取符合以下内容的行:

  

String1 A
  String2 B
  String3 C

等。

并将它们存储在两个独立的结构数组中; stringName和group。 我发现的所有内容都是用符号或其他类似的代码分隔的字符串,但不是同一个问题

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include <math.h>
#include "string.h"

struct StringStruct {
    char    Stringname[16];
    char    group[1];
}String[100];

int MaxNumLines = 100, i;
char str[25];

int main()
{
    // open String.dat file as a read from file
    FILE *fp1;
    errno_t string_file = fopen_s(&fp1, "String.dat", "r");

    // if String.dat not found,
    if (fp1 == NULL)
    {
        // print error
        printf_s("Error: String.dat not found\n");
        exit(0);
    }
    // if String.dat found
    else
    {
        // print success
        printf_s("File String.dat opened successfully\n");
    }

    // read names and assign groups
    while (fscanf_s(fp1, "%s %s", String[i].Stringname, String[i].group) != EOF)
    {
        // read names one line at a time
        for (i = 0; i < MaxNumLines; i++)
        {
            // read string name
            scanf_s(str, "%s %s", String[i].Stringname, String[i].group);
        }    

    }
    for (i = 0; i < MaxNumLines; i++)
    {
        printf_s("%-12s", String[i].Stringname);
        printf_s("%s", String[i].group);
    }
}

}

现在,在我看来,一切都应该有效,但事实并非如此,而且我也得到了fscanf_s警告:

  
      
  • 警告C4477:&#39; fscanf_s&#39; :格式字符串&#39;%s&#39;需要类型为&#39; unsigned int&#39;的参数,但是可变参数2的类型为&#39; char *&#39;
  •   
  • 注意:此参数用作缓冲区大小
  •   
  • 警告C4473:&#39; fscanf_s&#39; :没有为格式字符串
  • 传递足够的参数   
  • 注意:占位符及其参数需要4个可变参数,但提供了2个
  •   
  • 注意:格式字符串&#39;%s&#39;
  • 需要缺少可变参数3   
  • 注意:此参数由转换说明符
  • 使用   

但是我已经查看了fscanf_s函数,所有内容似乎都符合它的使用说明。

我不是最熟练的C,但到目前为止我一直在学习它,而且我一直试图找到解决这些问题的方法。几天,但在那个时候没有取得任何进展。

3 个答案:

答案 0 :(得分:0)

使用scanf_s系列函数时,格式说明符%s%c%[期望两个参数,而不是一个。第一个是指向应该存储数据的缓冲区的指针,第二个是该缓冲区的大小。

对于您的代码,它看起来像这样:

fscanf_s(fp1, "%s %s", String[i].Stringname, 16, String[i].group, 1)

请注意,常规scanf系列函数只接受这些格式的一个参数(指向缓冲区的指针)。

可以找到有关这些功能的更多信息here

答案 1 :(得分:0)

  1. 更正建议: 1)明确要求:扫描是从键盘扫描输入,这里你想从文件中读取字符串,所以不要使用扫描 2)清除逻辑:在逐行处理读取文件的循环中,不应再使用'for'循环。在这里你最好记住,文件映射一行结构对象 3)良好的名称约定:数组名称'String'不是一个好名字 4)可重用代码:数组的长度应与文件的行数对齐。 5)手动清理:打开后总是关闭文件,在malloc后释放内存。
  2. 如果您不需要处理设备/硬件,最好学习Python,这样可以更好地处理文本。指针和c的记忆有点复杂。
  3. #include "stdio.h"
    #include "stdlib.h"
    #include <math.h>
    #include "string.h"
    
    struct  Stringstruct
    {
        char    Stringname[16];
        char    *group;
    };
    
    
    int MAX_LINE = 100;// max count of chars in one line
    
    int main()
    {
        // open String.dat file as a read from file
        FILE *fp1;
        errno_t string_file = fopen_s(&fp1, "String.dat", "r"); 
        char *sep = " \n";//split the string line into tokens.
        char *token = NULL;
        char *next_token = NULL;  
        char buf[100];//100 is the max chars number of one line
    
        if (fp1 == NULL) {
            // print error
            printf_s("Error: String.dat not found\n");
            exit(0);
        }
        else
        {
            // print success
            printf_s("File String.dat opened successfully\n");
        }
    
        //get the line count of the file, allocate memory to the array dynamically
        int linecount = 0; 
        while (fgets(buf, MAX_LINE, fp1) != NULL)
        {
            linecount++;
        }
        struct Stringstruct  *myarray = malloc(sizeof(struct Stringstruct)* linecount);
    
        //back to the start of the file and process the strings line by line
        rewind(fp1);
    
        int i = -1;
        while (fgets(buf, sizeof(buf), fp1))//read the file line by line
        { 
            i++;
            token = strtok_s(buf, sep, &next_token); 
            int temp = strlen(token);
            strcpy_s(myarray[i].Stringname, strlen(token)+1, token); 
    
            //since there's newline chars at the end of the string line, like '\n' or '\r\n'
            //normally it will loop for two times, 
            //add the exception processing in this block
            while (token != NULL) 
            {
                // Get next token: 
                if (token != NULL)
                {
                    //printf(" %s\n", token);
                    token = strtok_s(NULL, sep, &next_token);  
                    int temp = strlen(token);
                    myarray[i].group = malloc(sizeof(char));
                    strcpy_s(myarray[i].group, strlen(token) + 1, token); 
                    break;
                }
            }
    
            //if the index exceed, stop the loop
            if (i >= linecount) {
                printf_s("Error: array mystring over flow\n");
                break;
            }         
        }
    
        fclose(fp1);//close the file
    
        for (i = 0; i < linecount; i++)
        {
            printf_s("%-12s", myarray[i].Stringname);
            printf_s("%s\n", myarray[i].group);
            myarray[i].group = NULL;
        }
    
        free(myarray);
        myarray = NULL;
    
        system("PAUSE");
    
        return 0; 
    }
    

答案 2 :(得分:0)

奥卡姆剃刀。我不确定我的问题是否明确,但我发现了一个非常简单的解决方案:

for(i=0;i<num_strings;i++)
{
    fscanf_s(fp, "%16s", String[i].name, 16);
    fscanf_s(fp, "%2s", String[i].group, 2);
}

16是最大名称长度+ ~2,2是组字符串的舒适大小。

将这些打印在另一个for循环中确认它们起作用,至少对我来说。 对不起,如果这对退伍军人来说是一种显而易见的方法,但是作为我的新手,我不知道该问什么。

感谢那些帮助过的人!