2

I'm trying to scanf sql table without using scanf for every symbol, but my code outputs some kind of trash. Input

8
"Peter Falk" 1927 "USA"
"Oleg Tabakov" 1935 "USSR"
"Andrei Mironov" 1941 "USSR"
"Arnold Schwarzenegger" 1947 "USA"
"Jean Reno" 1948 "France"
"Sharon Stone" 1958 "USA"
"Tom Cruise" 1962 "USA"
"Ryoko Hirosue" 1980 "Japan"

My code

#include <stdio.h>
#include <stdlib.h>

typedef struct ActorBio {
    char name[35];
    int BirthYear;
    char country[15];
} ActorBio;


int main() {
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    int n1;
    scanf("%d", &n1);
    ActorBio *actors = malloc(sizeof(ActorBio) * (n1 + 2));
    getchar();
    for (int i = 0; i < n1; i++) {
        scanf("%[^34]s\n", actors[i].name);
        scanf("%d\n",&actors[i].BirthYear);
        gets(actors[i].country);
        printf("%s %d %s\n",actors[i].name,actors[i].BirthYear,actors[i].country);
    }
    return 0;
}

I use scanf("%[^34]s\n", actors[i].name); to scanf until 34(asci code of "), but it just scanfs everything.Then i scanf int data and then country. How should i change this part to scanf only name? My output is

"Peter Falk" 1927 "USA"
"Oleg Tabako# 35 "USSR"
"Andrei Mironov" 19 41 "USSR"
"Arnold Schwarzenegger" 19 47 "USA"
"Jean Reno" 19 48 "France"
"Sharon Stone" 1958 "USA"
"Tom Cruise" 1962 "USA"
"Ryoko Hirosue" 1980 "Japan" 824189541 962 "USA"
"Ryoko Hirosue" 1980 "Japan"
 Hirosue" 1980 "Japan" 0 
 0 
 0 

I want my struct ActorBio to save information correctly and to use scanfs instead of while loops.

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • 2
    The scan set `%[^34]` looks for not digit 3 or 4. To avoid quotes, you need `%[^\”]` instead. – Jonathan Leffler Dec 16 '21 at 06:54
  • 2
    In addition to Jonathans comment: I suspect that the "s" in `"%[^34]s\n"` does not what you think it does. Maybe reread the specification of scanf(). It might also spark you to not ignore the return value. – Yunnosch Dec 16 '21 at 07:04
  • 1
    Besided that you should never use `gets`. It is considered dangerous and was removed from C standard long ago. Use `fgets` instead. – Gerhardh Dec 16 '21 at 07:28
  • Don't mix you input methods. And `scanf("%[^34]s\n", actors[i].name);` is also wrong because: `%[]` format isn't a subset of `%s`; and there should not be [trailing whitespace](https://stackoverflow.com/questions/19499060/what-is-the-effect-of-trailing-white-space-in-a-scanf-format-string) in the format string. Also 15 is a bit tight for all country names. – Weather Vane Dec 16 '21 at 07:35
  • 1
    Horribly, like this: `res = scanf(" %*[^A-Z] %34[^\"]\" %d %*[^A-Z] %14[^\"]\"", name, &year, country);` – Weather Vane Dec 16 '21 at 08:22

1 Answers1

0
int n1;
scanf("%d", &n1);

There is still one \n character in the buffer, this will be read the next time. You can skip it with scanf("%d\n", &n1)

You also want to make sure the function succeeded, otherwise n1 is not initialized. You only need to allocate n1 items.

int n1;
if (scanf("%d\n", &n1) != 1) 
{ printf("format error\n"); return 0; }

ActorBio* actors = malloc(sizeof(ActorBio)* n1);
if (!actors) { return 0; }

for (int i = 0; i < n1; i++)
{
    if (3 != scanf("\"%34[^\"]\" %d \"%14[^\"]\"\n", 
        actors[i].name, &actors[i].BirthYear, actors[i].country))
        continue;
    printf("%s %d %s\n", actors[i].name, actors[i].BirthYear, actors[i].country);
}

Alternatively you can use fgets and strtok

char buf[1024];
for (int i = 0; i < n1;)
{
    if (!fgets(buf, sizeof(buf), stdin))
        break;
    
    memset(&actors[i], 0, sizeof(ActorBio));

    char* token;
    token = strtok(buf, "\"");
    if (!token) continue;
    strncpy(actors[i].name, token, sizeof(actors[i].name) - 1);

    token = strtok(NULL, " ");
    if (!token) continue;
    actors[i].BirthYear = atoi(token);

    token = strtok(NULL, "\"");
    if (!token) continue;
    strncpy(actors[i].country, token, sizeof(actors[i].country) - 1);

    printf("%s %d %s\n", actors[i].name, actors[i].BirthYear, actors[i].country);

    i++;
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77