【问题标题】:ASCII characters not getting printed outASCII 字符没有被打印出来
【发布时间】:2018-12-23 00:20:14
【问题描述】:

我想从输入文件中读取卡片并打印出它们的值。

但是,当我尝试打印字符时,它会打印出 '0'

如果我打印出字符 'A',那么通常应该打印出 int 值 65,因为我将字符 'A' 存储为 Int。

谁能帮帮我?

提前谢谢你。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define max 100
#define MAX_LENGTH 14

int main(){
  char *lines = malloc(max*sizeof(char));

    char **colour = malloc(max*sizeof(char));
    int *value =malloc(max*sizeof(int));
    FILE *fp;
    fp = fopen("config2.txt", "r");
    if(fp == NULL){
        printf("Cannot open filelist.txt\n");
        return 1;
    }
    int i= 0;
    while (i < max && fgets(lines, MAX_LENGTH, fp) != NULL) { 
        colour[i] = malloc(MAX_LENGTH); 
        sscanf(lines, "%s %d", colour[i], &value[i]);
        printf("%s\n", colour[i]);
        printf("%d\n", value[i]);

        i++;
    }
    return 0;
}

输入:

RED A
RED 2
RED 3
RED 4
RED 5
RED 6
RED 7
RED 8
RED 9
RED 10
RED J
RED Q
RED K

【问题讨论】:

  • 我首先检查sscanf 的返回值。如果您没有正确读取数据,则无法正确打印。
  • @Retired Ninja sscanf 的返回值可以是 null,0 或 1 我认为在我的情况下它是 0。我不明白我是如何没有正确读取数据的。
  • @momonosu 您要求它读取带有 %d 的 int,但提供的字母不是数字,即“A”。因此,它无法正确读取。
  • 正如@Serge 所说,%d 无法读取字母,但您还有其他问题。 char **colour = malloc(max*sizeof(char)); 必须是 char **colour = malloc(max*sizeof(char*));,因为您将指针分配给字符,而不是字符。如果sscanf 没有返回 2,那么您没有正确读取数据。
  • OT:关于:printf("Cannot open filelist.txt\n"); return 1; 1) 错误消息应该输出到stderr,而不是stdout。 2)当错误指示来自C库函数时,还应输出系统认为发生错误的文本原因。一个很好的方法是:perror( "foen failed" ); exit( EXIT_FAILURE );

标签: c arrays string pointers


【解决方案1】:

您处理'A' 或整数作为值的主要问题源于对A 可以使用"%d" 解析sscanf 的误解格式说明符,它可以不。为什么?当您尝试用"%d" 解析'A' 时,会发生匹配失败,不会从输入缓冲区中提取更多字符,sscanfreturn 将是失败前发生的成功转换次数。

当您有不同类型的数据时,例如

RED A
RED 2

为了解析A2 的值,它需要两个不同的sscanf 表达式,您可以通过检查 return 轻松区分它们强>为sscanf。您在有条件的情况下执行此操作,如果使用 "%s %d" 解析失败,您将尝试使用 "%s %c" 解析并验证是否成功。

例如,假设不是使用malloc 进行分配(无论如何您都不会重新分配),您只需声明一个结构数组来保存从每一行读取的colorvalue,例如

...
#define MAXCOLR   14
#define MAXLINE  100
#define MAXCHR  1024    /* don't skimp on read buffer size */

typedef struct {        /* simple struct to associate each color/value */
    char color[MAXCOLR];
    int value;
} colorval_t;

int main (int argc, char **argv) {

    size_t ndx = 0;     /* index */
    char buf[MAXCHR];   /* read buffer */
    colorval_t arr[MAXLINE] = {{ .color = "" }};    /* array of struct */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    ...
    while (ndx < MAXLINE && fgets (buf, MAXCHR, fp)) {
        char c;     /* temp char to use for parsing 2nd case */
        if (sscanf (buf, "%13s %d", arr[ndx].color, &arr[ndx].value) == 2)
            ndx++;
        else if (sscanf (buf, "%13s %c", arr[ndx].color, &c) == 2) {
            arr[ndx].value = c;
            ndx++;
        }
    }

上面的while 循环是处理从每行读取的信息解析到buf 的操作代码。第一个sscanf 调用尝试解析为字符串和整数值。如果返回不是2,则第二次调用sscanf 以尝试将内容解析为字符串和字符。如果成功,则将字符值(例如字符的 ASCII 值)分配给 value,从您的问题来看,这似乎是您想要的。

添加一些验证,然后为arr 中包含的每个结构输出colorvalue,您可以执行以下操作。 (注意:程序将要读取的文件名作为第一个参数,如果没有给出参数,则默认从stdin 读取。不要对文件名进行硬编码。将文件名作为参数或提示传递进入)

#include <stdio.h>

#define MAXCOLR   14
#define MAXLINE  100
#define MAXCHR  1024    /* don't skimp on read buffer size */

typedef struct {
    char color[MAXCOLR];
    int value;
} colorval_t;

int main (int argc, char **argv) {

    size_t ndx = 0;
    char buf[MAXCHR];
    colorval_t arr[MAXLINE] = {{ .color = "" }};
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (ndx < MAXLINE && fgets (buf, MAXCHR, fp)) {
        char c;
        if (sscanf (buf, "%13s %d", arr[ndx].color, &arr[ndx].value) == 2)
            ndx++;
        else if (sscanf (buf, "%13s %c", arr[ndx].color, &c) == 2) {
            arr[ndx].value = c;
            ndx++;
        }
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (size_t i = 0; i < ndx; i++)
        printf ("arr[%2zu] : %-14s %d\n", i, arr[i].color, arr[i].value);

    return 0;
}

注意:使用field-width修饰符13来保护color的字符数组边界)

使用/输出示例

使用您的数据作为输入会产生以下结果:

$ ./bin/rdcolorval <dat/colorval.txt
arr[ 0] : RED            65
arr[ 1] : RED            2
arr[ 2] : RED            3
arr[ 3] : RED            4
arr[ 4] : RED            5
arr[ 5] : RED            6
arr[ 6] : RED            7
arr[ 7] : RED            8
arr[ 8] : RED            9
arr[ 9] : RED            10
arr[10] : RED            74
arr[11] : RED            81
arr[12] : RED            75

检查一下,如果您还有其他问题,请告诉我。

【讨论】:

  • 非常感谢您的回答。我很难理解这个colorval_t arr[MAXLINE] = {{ .color = "" }}; 确实
  • 如果您查看typedef 中的stuct,它被命名为colorval_t。所以colorval_t arr[MAXLINE] 只是用MAXLINE 元素声明了一个结构数组(名为arr)。 named initializer 使用{{ .color = "" }}; 简单地将数组中每个元素的color 成员初始化为空字符串(全零),默认情况下,所有value 成员都被初始化为零好。 (所以它只是声明一个结构数组并将所有元素初始化为零)使用结构来协调colorvalue比使用多个数组更干净。
  • 我现在明白了。非常感谢:)
【解决方案2】:

以下建议的代码:

  1. 不保留每一行的内容,而只保留当前行的内容。你可能想改变它
  2. 正确检查错误
  3. 不使用动态内存分配。你可能想改变它
  4. 干净编译
  5. 不包括那些内容没有使用的头文件
  6. 在正常退出或调用 sscanf() 失败时正确清理(关闭文件)。
  7. 使用main() 的有效签名
  8. 使用所有大写的定义值的约定
  9. 在输入格式说明符%s 上正确使用 MAX CHARACTERS 修饰符,以避免任何可能的缓冲区溢出和由此产生的未定义行为
  10. 记录包含每个头文件的原因
  11. 不纠正传入数据与sscanf() 调用之间的不匹配 强烈建议您阅读atoi()strtol() 并修改对sscanf() 的调用以期望两个字符序列并相应地保存它们。

现在,建议的代码:

#include <stdio.h>   // printf(), fprintf(), sscanf()
#include <stdlib.h>  // exit(), EXIT_FAILURE


//#define MAX_LINES 100
#define MAX_LENGTH 14


int main( void )
{
    char lines[ MAX_LENGTH +1];
    char colour[ MAX_LENGTH ];

    int  value;

    FILE *fp = fopen( "config2.txt", "r" );
    if(fp == NULL)
    {
        perror( "fopen to read config2.txt failed" );
        exit( EXIT_FAILURE );
    }


    while ( fgets( lines, MAX_LENGTH, fp ) ) 
    {   
        if( sscanf(lines, "%100s %d", colour, &value) != 2 )
        {
            fprintf( stderr,  "sscanf to extract two fields from input line failed\n" );
            fclose( fp );
            exit( EXIT_FAILURE );
        }

        printf( "colour: %s\n", colour );
        printf( "value:  %d\n", value );
    }
    fclose( fp );
    return 0;
}

【讨论】:

  • 一个非常详细的答案(很好),但它不能解决 OP 的问题。执行程序只是给出:“sscanf 从输入行中提取两个字段失败”。一些挑剔的 cmets:a) lines 不需要 MAX_LENGTH +1 b) 即使避免使用 %s 进行扫描是一个好习惯,这种情况也不需要 %100s,因为 colour 的大小与lines.
  • @4386427,我确实提到过 OP 需要修改发布的答案以读取两个字符串,并且 OP 需要处理第二个字符串的转换(如果它是数字)
【解决方案3】:

您的代码与可行的代码非常接近。主要问题是您可以使用格式说明符“%s %d”扫描像“RED A”这样的行,因为 A 不是整数。相反,您可以使用字符对其进行扫描。

此外,您对colourmalloc 有疑问。你需要 sizeof(char*) 因为你想要一个 char 指针数组。

所以尝试一下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define max 100
#define MAX_LENGTH 14

int main(){
  char *filename = "config2.txt";
  char *lines = malloc(max*sizeof(char));
  char **colour = malloc(max*sizeof(char*));  // Use sizeof(char*)
  char *value =malloc(max*sizeof(char));      // Use char instead of int
  FILE *fp;

  fp = fopen(filename, "r");
  if(fp == NULL){
    fprintf(stderr, "Cannot open %s : ", filename);
    perror("");
    exit(1);
  }

  int i= 0;
  while (i < max && fgets(lines, MAX_LENGTH, fp) != NULL) {
    colour[i] = malloc(MAX_LENGTH);
    if (sscanf(lines, "%s %c", colour[i], &value[i]) != 2)  // Use %c instead of %d and check return value
    {
      printf("Unexpected input file data\n");
      exit(1);
    }
    printf("%s ", colour[i]);
    printf("%c (%d)\n", value[i], value[i]);       // Print value as both char and int

    i++;
  }

  // Clean up
  fclose (fp);
  for (int j = 0; j<i; ++j) free(colour[j]);
  free(colour);
  free(value);

  return 0;
}

输出:

RED A (65)
RED 2 (50)
RED 3 (51)
RED 4 (52)
RED 5 (53)
RED 6 (54)
RED 7 (55)
RED 8 (56)
RED 9 (57)
RED 1 (49)
RED J (74)
RED Q (81)
RED K (75)

还请注意,您应该始终检查malloc 的返回值。示例:

SomeType *someVar = malloc(sizeof(SomeType));  // or better malloc(sizeof *momeVar);
if (someVar == NULL)
{
    // Out of memory - add error handling (e.g. terminate program)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多