Thread: Program (probably scanf) provides corrupted strings after 2nd loop.

  1. #1
    Registered User
    Join Date
    Jan 2022
    Posts
    4

    Program (probably scanf) provides corrupted strings after 2nd loop.

    Hello,
    the following program receives a string using scanf and saves the first word of the string on com and every other parameter to param[i]. It extracts the parameters to string if they are in "" or to integers if they are not. For example, if it receives input:
    add "test" 2021 "genre" "actor 1, actor 2"

    , it will save them like this:

    com=add
    param[1]=test
    param[2]=2021 (int)
    param[3]=genre
    param[4]=actor 1, actor 2
    param[5]=add

    The program works fine during the first scanf, but on the second it provides wrong strings/values.

    Console:
    add "title" 2021 "genre" "actor" [input on first scanf]
    com add [\/ Output correct \/]

    title title
    year 2021
    genre genre
    actors actor
    add "new" 2020 "newgenre" "newactor" [input on second scanf]
    com a [\/ Wrong output \/]
    title ddtle
    year 0
    genre 2020e
    actors newgenre

    What may be wrong. As i said, it works fine on the first run but not on loop runs.

    Note: This is just the main function, the rest of the program is not posted since it's not really needed for that problem - i suppose...

    Thanks

    Code:

    Code:
    int main(int argc, char *argv[])
    {
      int year, castsize, i, flag = 0, words = 1, j = 0, p, k, length = 0;
      char *title, *genre, *actors, cmd[500], com[20], param[5][500], getcmd[500];
      movie_t *ptr, *found;
      ptr = NULL;
      ptr =
          initialize(ptr, argc, argv, param, year, castsize, title, genre, actors);
      do {
        for (i = 0; i < 20; i++)
          com = '\0';
        for (p = 0; p++; p < 4) {
          for (i = 0; i < 500; i++) {
            cmd = '\0';
            param[p] = '\0';
          }
        }
        i = 0;
        p = 0;
        scanf(" %500[^\n]s", &getcmd);
        strcpy(cmd, getcmd);
        while (cmd != '\0') {
          if (cmd == ' ') {
            words++;
          } else {
            param[4] = cmd;
            com = param[4];
          }
          if (words > 1)
            break;
          i++;
        }
        while (cmd[j] != '\0') {
          length++;
          j++;
        }
        if (words > 1) {
          while (i < length && p < 4) {
            k = 0;
            if (cmd[i + 1] == '"') {
              i += 2;
              for (j = 0; j++; j < 500)
                param[p][j] = '\0';
              while (cmd != '"') {
                param[p][k] = cmd;
                i++;
                k++;
              }
              i++;
            } else {
              i++;
              for (j = 0; j++; j < 500)
                param[p][j] = '\0';
              while (cmd != ' ' && cmd != '\0') {
                param[p][k] = cmd;
                i++;
                k++;
              }
            }
            p++;
          }
        }
        printf("com %s\ntitle %s\nyear %d\ngenre %s\nactors %s\n", com, *(param),
               atoi(*(param + 1)), *(param + 2), *(param + 3));
        flag = checkcmd(com);
        if (flag = 0)
          continue;
        if (strcmp(com, "add") == 0) {
          title = *(param);
          year = atoi(*(param + 1));
          genre = *(param + 2);
          castsize = calc_actors(param, 3);
          actors = *(param + 3);
          ptr = add_movie(title, year, genre, castsize, actors, ptr);
        } else if (strcmp(com, "update") == 0) {
          title = *(param);
          found = search(ptr, title, &flag);
          if (flag = 0)
            continue;
          if (found == NULL) {
            continue;
          }
          update(found, param);
        } else if (strcmp(com, "delete") == 0) {
          title = *(param);
          found = search(ptr, title, &flag);
          if (flag = 0)
            continue;
          if (found == NULL) {
            continue;
          }
          delete(ptr, title);
        } else if (strcmp(com, "export") == 0) {
          export(ptr, param);
        } else {
          continue;
        }
      } while (strcmp(cmd, "exit") != 0);
    }
    Last edited by Salem; 01-06-2022 at 11:10 PM. Reason: Removed crayola

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Post code as plain text (you've posted a bunch of markup along with it).
    Post the whole program so we can run it.
    Always compile your program with a high warning level (e.g., gcc -Wall -Wextra -Wpedantic ...) and fix all warnings.

    A high warning level should point out that you've said
    if (flag=0) continue;
    in a couple of places (= should be ==)
    and you've mixed up the order of the test part and update part of your if statements in a couple of places, for example,
    for (p=0; p++; p<4)
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > Program (probably scanf) provides corrupted strings after 2nd loop.
    It's always the standard library used by millions every day without issue that's always a "problem".

    Never the noob with code full of errors.
    Code:
    $ gcc -Wall -Wextra foo.c
    foo.c: In function ‘main’:
    foo.c:15:11: error: assignment to expression with array type
       15 |       com = '\0';
          |           ^
    foo.c:16:24: warning: statement with no effect [-Wunused-value]
       16 |     for (p = 0; p++; p < 4) {
          |                      ~~^~~
    foo.c:18:13: error: assignment to expression with array type
       18 |         cmd = '\0';
          |             ^
    foo.c:19:18: error: assignment to expression with array type
       19 |         param[p] = '\0';
          |                  ^
    foo.c:24:19: warning: format ‘%[^
       ’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[500]’ [-Wformat=]
       24 |     scanf(" %500[^\n]s", &getcmd);
          |             ~~~~~~^~     ~~~~~~~
          |                   |      |
          |                   char * char (*)[500]
    foo.c:27:15: warning: comparison between pointer and integer
       27 |       if (cmd == ' ') {
          |               ^~
    foo.c:30:18: error: assignment to expression with array type
       30 |         param[4] = cmd;
          |                  ^
    foo.c:31:13: error: assignment to expression with array type
       31 |         com = param[4];
          |             ^
    foo.c:46:30: warning: statement with no effect [-Wunused-value]
       46 |           for (j = 0; j++; j < 500)
          |                            ~~^~~~~
    foo.c:48:22: warning: comparison between pointer and integer
       48 |           while (cmd != '"') {
          |                      ^~
    foo.c:49:25: warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
       49 |             param[p][k] = cmd;
          |                         ^
    foo.c:56:30: warning: statement with no effect [-Wunused-value]
       56 |           for (j = 0; j++; j < 500)
          |                            ~~^~~~~
    foo.c:58:22: warning: comparison between pointer and integer
       58 |           while (cmd != ' ' && cmd != '\0') {
          |                      ^~
    foo.c:59:25: warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
       59 |             param[p][k] = cmd;
          |                         ^
    The surprise is that it managed to run once with all this going on, not that it failed on the second iteration.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    There is a problem with the scanf format string. You've put an extraneous "s" after the format. And the size should be one less than the char array size. So it should be:
    Code:
            scanf(" %499[^\n]", getcmd);
    Note that you don't need the ampersand since the name of an array is converted to a pointer in most contexts. Also, I don't see the point of reading it into getcmd just to copy it to cmd. May as well read it directly into cmd.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    Jan 2022
    Posts
    4
    I compiled it using: gcc -ansi -pedantic - Werror
    and it was compiled normally, with no errors (for some reason...).

  6. #6
    Registered User
    Join Date
    Jan 2022
    Posts
    4
    Here's the whole code:

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    
    struct movie {
        char *title;
        int year;
        char *genre;
        int castsize;
        char *actors;
        struct movie *next;
    };
    
    typedef struct movie movie_t;
    
    FILE *fp;
    
    int calc_actors (char param[][500], int collumn) {
        int i, len, actors=1;
        len=strlen(*(param+collumn));
        for (i=0; i<len; i++) {
            if (param[collumn][i]==',') actors++;
        }
        return actors;
    }
    
    void cmd_line(char param[][500], char com[]) {
        int words=1, i, j=0, p, k, length=0;
        char cmd[500];
        for (i=0; i<20; i++) com[i]='\0';
        for (p=0; p++; p<4) {
            for (i=0; i<500; i++) {
                cmd[i]='\0';
                param[p][i]='\0';
            }
        }
        i=0;
        p=0;
        scanf("%500[^\n]s", &cmd);
        printf("%s\n", cmd);
        while (cmd[i]!='\0') {
            if (cmd[i]==' ') {
                words++;
            } else {
                param[4][i]=cmd[i];
            }
            if (words>1) break;
            i++;
        }
        while (cmd[j]!='\0') {
            length++;
            j++;
        }
        printf("\nlength%d, i %d, %d words, com %s\n", length, i, words, *(param+4));
        if (words>1) {
            while (i<length) {
                k=0;
                if (cmd[i+1]=='\"') {
                    i+=2;
                    for (j=0; j++; j<500) param[p][j]='\0';
                    while (cmd[i]!='\"') {
                        param[p][k]=cmd[i];
                        i++;
                        k++;
                    }
                    i++;
                    printf("\" %s\n", *(param+p));
                } else {
                    i++;
                    for (j=0; j++; j<500) param[p][j]='\0';
                    while (cmd[i]!=' ' && cmd[i]!='\0') {
                        param[p][k]=cmd[i];
                        printf("i %d ", i);
                        i++;
                        k++;
                    }
                    printf("sp %s\n", *(param+p));
                }
                p++;
                printf("p %d\n", p);
            }
        }
        printf("com %s\ntitle %s\nyear %d\ngenre %s\nactors %s\n", com, *(param), atoi(*(param+1)), *(param+2), *(param+3));
    }
    
    movie_t *search(movie_t *ptr, char *title, int *flag) {
        while((ptr!=NULL) && (strcmp(title, ptr->title)!=0)) {
            ptr=ptr->next;
        }
        if (ptr==NULL) {
            *flag=0;
        } else {
            *flag=1;
        }
        return ptr;
    }
    
    void delete(movie_t *ptr, char *title) {
        movie_t *prev;
        prev=ptr;
        while((ptr!=NULL) && (strcmp(title, ptr->title)!=0)) {
            prev=ptr;
            ptr=ptr->next;
        }
        if (ptr!=NULL) {
            prev->next=ptr->next;
            free(ptr);
        }
    }
    
    void update(movie_t *ptr, char param[][500]) {
        char field[10];
        strcpy(field, *(param+1));
        if (strcmp(field, "Year")==0) {
            ptr->year=atoi(*(param+2));
        } else if (strcmp(field, "Genre")==0) {
            free(ptr->genre);
            ptr->genre = (char*) malloc(strlen(*(param+2)) + 1);
            strcpy(ptr->genre, *(param+2));
        } else if (strcmp(field, "Actors")==0) {
            strcpy(ptr->actors, *(param+2));
            ptr->castsize=calc_actors(param, 2);
        }
    }
    
    int checkcmd(char *com) {
        if ((strcmp(com, "add")!=0) &&
            (strcmp(com, "delete")!=0) &&
            (strcmp(com, "update")!=0) &&
            (strcmp(com, "exit")!=0) &&
            (strcmp(com, "export")!=0)) 
            {
            return 0;
        } else {
            return 1;
        } 
    }
    
    movie_t *add_movie(char *title, int year, char *genre, int castsize, char *actors, movie_t *ptr) {
        movie_t *new;
        new=(movie_t *) malloc(sizeof(movie_t));
        new->title = (char*) malloc(strlen(title) + 1);
        strcpy(new->title, title);
        new->year = year;
        new->genre = (char*) malloc(strlen(genre) + 1);
        strcpy(new->genre, genre);
        new->castsize  = castsize;
        new->actors = (char*) malloc(strlen(actors) + 1);
        strcpy(new->actors, actors);
        new->next = ptr;
        return new;
    }
    
    void import_file(char line[], char param[][500]) {
        int i, j=0, k, len, last=0, col;
        for (i=0; i<4; i++) {
            for (j=0; j<500; j++) param[i][j]='\0';
        }
        i=0;
        j=0;
        for (col=0; col<3; col++) {
            while (line[j]!=',') j++;
            for (k=0; i<j; i++, k++) param[col][k]=line[i];
            i=j+1;
            j++;
        }
        while (line[i]!='[') i++;
        i++;
        k=0;
        while (line[i]!=']') {
            param[3][k]=line[i];
            i++;
            k++;
        }
    }
    
    movie_t *initialize(movie_t *ptr, int argc, char **argv, char param[][500],
                        int year, int castsize, char *title, char *genre, char *actors) {
        int i;
        char filename[256], line[500];
        if (argc==1) {
            return NULL;
        } else if (argc==3) {
            if (strcmp(*(argv+1), "import") == 0) {
                snprintf(filename, sizeof(filename), "%s", *(argv+2));
                fp=fopen(filename, "r");
                fgets(line,500,fp);
                do {
                    for (i=0; i<500; i++) line[i]='\0';
                    fgets(line, 500, fp);
                    import_file(line, param);
                    title=*(param);
                    year=atoi(*(param+1));
                    genre=*(param+2);
                    castsize=calc_actors(param, 3);
                    actors=*(param+3);
                    ptr=add_movie(title, year, genre, castsize, actors, ptr);
                } while(fgets(line, 500, fp)!=NULL);
                fclose(fp);
            } else {
                exit(0);
            } 
        } else {
            exit(0);
        }
        return ptr;
    }
    
    void export(movie_t *ptr, char param[][500]) {
        char filename[256];
        movie_t *prev, *next;
        snprintf(filename, sizeof(filename), "%s", *(param));
        fp = fopen(filename, "w");
        fprintf(fp, "Title,Year,Genre,CastSize,Actors\n");
        prev=NULL;
        next=NULL;
        while (ptr!=NULL) {
            next = ptr->next;
            ptr->next = prev;
            prev = ptr;
            ptr = next;
        }
        ptr=prev;
        while (ptr!=NULL) {
            fprintf(fp, "%s,%d,%s,%d,[%s]\n", 
                ptr->title, ptr->year, ptr->genre, ptr->castsize, ptr->actors);
            ptr=ptr->next;
        }
        fclose(fp);
        prev=NULL;
        next=NULL;
        while (ptr!=NULL) {
            next = ptr->next;
            ptr->next = prev;
            prev = ptr;
            ptr = next;
        }
        ptr=prev;
    }
    
    int main (int argc, char *argv[]) {
        int year, castsize, i, flag=0, words=1, j=0, p, k, length=0;
        char *title, *genre, *actors, cmd[500], com[20], param[5][500], getcmd[500];
        movie_t *ptr, *found;
        ptr = NULL;
        ptr = initialize(ptr, argc, argv, param, year, castsize, title, genre, actors);
        do {
            for (i=0; i<20; i++) com[i]='\0';
            for (p=0; p++; p<4) {
                for (i=0; i<500; i++) {
                    cmd[i]='\0';
                    param[p][i]='\0';
                }
            }
            i=0;
            p=0;
            scanf(" %500[^\n]s", &getcmd);
            strcpy(cmd, getcmd);
            while (cmd[i]!='\0') {
                if (cmd[i]==' ') {
                    words++;
                } else {
                    param[4][i]=cmd[i];
                    com[i]=param[4][i];
                }
                if (words>1) break;
                i++;
            }
            while (cmd[j]!='\0') {
                length++;
                j++;
            }
            if (words>1) {
                while (i<length && p<4) {
                    k=0;
                    if (cmd[i+1]=='\"') {
                        i+=2;
                        for (j=0; j++; j<500) param[p][j]='\0';
                        while (cmd[i]!='\"') {
                            param[p][k]=cmd[i];
                            i++;
                            k++;
                        }
                        i++;
                    } else {
                        i++;
                        for (j=0; j++; j<500) param[p][j]='\0';
                        while (cmd[i]!=' ' && cmd[i]!='\0') {
                            param[p][k]=cmd[i];
                            i++;
                            k++;
                        }
                    }
                    p++;
                }
            }
            printf("com %s\ntitle %s\nyear %d\ngenre %s\nactors %s\n", com, *(param), atoi(*(param+1)), *(param+2), *(param+3));
            flag=checkcmd(com);
            if (flag=0) continue;
            if(strcmp(com, "add")==0) {
                    title=*(param);
                    year=atoi(*(param+1));
                    genre=*(param+2);
                    castsize=calc_actors(param, 3);
                    actors=*(param+3);
                    ptr = add_movie(title, year, genre, castsize, actors, ptr);
            } else if (strcmp(com, "update")==0) {
                title=*(param);
                found=search(ptr, title, &flag);
                if (flag==0) continue;
                if (found==NULL) {
                    continue;
                }
                update(found, param);
            } else if (strcmp(com, "delete")==0) {
                title=*(param);
                found=search(ptr, title, &flag);
                if (flag=0) continue;
                if (found==NULL) {
                    continue;
                }
                delete(ptr, title);
            } else if (strcmp(com, "export")==0) {
                export(ptr, param);
            } else {
                continue;
            }
        } while(strcmp(cmd, "exit") != 0);
    }

    Quote Originally Posted by john.c View Post
    Post code as plain text (you've posted a bunch of markup along with it).
    Post the whole program so we can run it.
    Always compile your program with a high warning level (e.g., gcc -Wall -Wextra -Wpedantic ...) and fix all warnings.

    A high warning level should point out that you've said
    if (flag=0) continue;
    in a couple of places (= should be ==)
    and you've mixed up the order of the test part and update part of your if statements in a couple of places, for example,
    for (p=0; p++; p<4)

  7. #7
    Registered User
    Join Date
    Jan 2022
    Posts
    4
    Isn't the "s" needed so that the input will be read as string and not as something else?
    I used to have "cmd" there instead of "getcmd". That getcmd was left there during the tests. I was trying to figure out what was going wrong.
    I know that my code may have many mistakes or it has many stuff that could be skipped... but im new on c programming...

    Quote Originally Posted by john.c View Post
    There is a problem with the scanf format string. You've put an extraneous "s" after the format. And the size should be one less than the char array size. So it should be:
    Code:
            scanf(" %499[^\n]", getcmd);
    Note that you don't need the ampersand since the name of an array is converted to a pointer in most contexts. Also, I don't see the point of reading it into getcmd just to copy it to cmd. May as well read it directly into cmd.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Something wrong with your setup if you're not getting any errors.
    Code:
    $ gcc -Wall -ansi -pedantic foo.c
    foo.c: In function ‘cmd_line’:
    foo.c:31:21: warning: statement with no effect [-Wunused-value]
       31 |     for (p=0; p++; p<4) {
          |                    ~^~
    foo.c:39:18: warning: format ‘%[^
       ’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[500]’ [-Wformat=]
       39 |     scanf("%500[^\n]s", &cmd);
          |            ~~~~~~^~     ~~~~
          |                  |      |
          |                  char * char (*)[500]
    foo.c:60:33: warning: statement with no effect [-Wunused-value]
       60 |                 for (j=0; j++; j<500) param[p][j]='\0';
          |                                ~^~~~
    foo.c:70:33: warning: statement with no effect [-Wunused-value]
       70 |                 for (j=0; j++; j<500) param[p][j]='\0';
          |                                ~^~~~
    foo.c: In function ‘import_file’:
    foo.c:155:25: warning: unused variable ‘last’ [-Wunused-variable]
      155 |     int i, j=0, k, len, last=0, col;
          |                         ^~~~
    foo.c:155:20: warning: unused variable ‘len’ [-Wunused-variable]
      155 |     int i, j=0, k, len, last=0, col;
          |                    ^~~
    foo.c: In function ‘initialize’:
    foo.c:185:13: warning: implicit declaration of function ‘snprintf’ [-Wimplicit-function-declaration]
      185 |             snprintf(filename, sizeof(filename), "%s", *(argv+2));
          |             ^~~~~~~~
    foo.c:4:1: note: ‘snprintf’ is defined in header ‘<stdio.h>’; did you forget to ‘#include <stdio.h>’?
        3 | #include<string.h>
      +++ |+#include <stdio.h>
        4 | 
    foo.c: In function ‘main’:
    foo.c:249:25: warning: statement with no effect [-Wunused-value]
      249 |         for (p=0; p++; p<4) {
          |                        ~^~
    foo.c:257:23: warning: format ‘%[^
       ’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[500]’ [-Wformat=]
      257 |         scanf(" %500[^\n]s", &getcmd);
          |                 ~~~~~~^~     ~~~~~~~
          |                       |      |
          |                       char * char (*)[500]
    foo.c:278:37: warning: statement with no effect [-Wunused-value]
      278 |                     for (j=0; j++; j<500) param[p][j]='\0';
          |                                    ~^~~~
    foo.c:287:37: warning: statement with no effect [-Wunused-value]
      287 |                     for (j=0; j++; j<500) param[p][j]='\0';
          |                                    ~^~~~
    foo.c:299:13: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
      299 |         if (flag=0) continue;
          |             ^~~~
    foo.c:318:17: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
      318 |             if (flag=0) continue;
          |                 ^~~~
    foo.c:329:1: warning: control reaches end of non-void function [-Wreturn-type]
      329 | }
          | ^
    foo.c:246:11: warning: ‘year’ is used uninitialized in this function [-Wuninitialized]
      246 |     ptr = initialize(ptr, argc, argv, param, year, castsize, title, genre, actors);
          |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    foo.c:246:11: warning: ‘castsize’ is used uninitialized in this function [-Wuninitialized]
    foo.c:246:11: warning: ‘title’ is used uninitialized in this function [-Wuninitialized]
    foo.c:246:11: warning: ‘genre’ is used uninitialized in this function [-Wuninitialized]
    foo.c:246:11: warning: ‘actors’ is used uninitialized in this function [-Wuninitialized]
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    No, you don't need the "s". Get rid of it.
    Also, compile with
    gcc -std=c99 -Wall -Wextra -Wpedantic -Werror ...
    A little inaccuracy saves tons of explanation. - H.H. Munro

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 7
    Last Post: 02-17-2018, 07:52 AM
  2. Help with scanf and strings
    By trueman1991 in forum C Programming
    Replies: 2
    Last Post: 11-14-2009, 07:03 AM
  3. Strings in Scanf function
    By dcwang3 in forum C Programming
    Replies: 21
    Last Post: 09-11-2008, 03:47 AM
  4. scanf for strings?
    By pobri19 in forum C Programming
    Replies: 7
    Last Post: 05-31-2008, 03:47 AM
  5. for loop ignoring scanf inside loop
    By xIcyx in forum C Programming
    Replies: 2
    Last Post: 04-17-2007, 01:46 AM

Tags for this Thread