Malloc and scanf

前端 未结 5 1906
攒了一身酷
攒了一身酷 2021-01-18 19:19

I\'m fairly competent in a few scripting languages, but I\'m finally forcing myself to learn raw C. I\'m just playing around with some basic stuff (I/O right now). How can

相关标签:
5条回答
  • 2021-01-18 19:49

    You need to give scanf a conversion format so it knows you want to read a string -- right now, you're just displaying whatever garbage happened to be in the memory you allocated. Rather than try to describe all the problems, here's some code that should at least be close to working:

    char *toParseStr = malloc(10);
    printf("Enter a string: ");
    scanf("%9s", toParseStr);
    printf("\n%s\n", toParsestr);
    /* Edit, added: */ 
    free(toParseStr);
    return 0;
    

    Edit: In this case, freeing the string doesn't make any real difference, but as others have pointed out, it is a good habit to cultivate nonetheless.

    0 讨论(0)
  • 2021-01-18 19:52

    Using scanf() (or fscanf() on data you don't control) with a standard "%s" specifier is a near-certain way to get yourself into trouble with buffer overflows.

    The classic example is that it I enter the string "This string is way more than 10 characters" into your program, chaos will ensue, cats and dogs will begin sleeping together and a naked singularity may well appear and consume the Earth (most people just state "undefined behaviour" but I think my description is better).

    I actively discourage the use of functions that cannot provide protection. I would urge you (especially as a newcomer to C) to use fgets() to read your input since you can control buffer overflows with it a lot easier, and it's more suited to simple line input than scanf().

    Once you have a line, you can then call sscanf() on it to your heart's content which, by the way, you don't need to do in this particular case since you're only getting a raw string anyway.

    I would use:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define BUFFSZ 10
    
    int main(int argc, char *argv[]) {
      char *toParseStr = malloc(BUFFSZ+2);
      if (toParseStr == NULL) {
          printf ("Could not allocate memory!\n");
          return 1;
      }
      printf ("Enter a string: ");
      if (fgets (toParseStr, BUFFSZ+2, stdin) == NULL) {
          printf ("\nGot end of file!\n");
          return 1;
      }
      printf("Your string was: %s",toParseStr);
      if (toParseStr[strlen (toParseStr) - 1] != '\n') {
          printf ("\nIn addition, your string was too long!\n");
      }
      free (toParseStr);
      return 0;
    }
    
    0 讨论(0)
  • 2021-01-18 19:56

    First, the errors that was keeping your program from working: scanf(3) takes a format-string, just like printf(3), not a string to print for the user. Second, you were passing the address of the pointer toParseStr, rather than the pointer toParseStr.

    I also removed the needless cast from your call to malloc(3).

    An improvement that your program still needs is to use scanf(3)'s a option to allocate memory for you -- so that some joker putting ten characters into your string doesn't start stomping on unrelated memory. (Yes, C will let someone overwrite almost the entire address space with this program, as written. Giant security flaw. :)

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
      char *toParseStr = malloc(10);
      printf("Enter a short string: ");
      scanf("%s",toParseStr);
      printf("%s\n",toParseStr);
      return 0;
    }
    
    0 讨论(0)
  • 2021-01-18 19:57

    You don't need an & before toParseStr in scanf as it is already a pointer

    also call free(toParseStr) afterwards

    0 讨论(0)
  • 2021-01-18 20:02
      char *toParseStr = (char*)malloc(10);
      printf("Enter string here: ");
      scanf("%s",toParseStr);
      printf("%s",toParseStr);
      free(toParseStr);
    

    Firstly, the string in scanf is specifies the input it's going to receive. In order to display a string before accepting keyboard input, use printf as shown.

    Secondly, you don't need to dereference toParseStr since it's pointing to a character array of size 10 as you allocated with malloc. If you were using a function which would point it to another memory location, then &toParseStr is required.

    For example, suppose you wanted to write a function to allocate memory. Then you'd need &toParseStr since you're changing the contents of the pointer variable (which is an address in memory --- you can see for yourself by printing its contents).

    void AllocateString(char ** ptr_string, const int n)
    {
        *ptr_string = (char*)malloc(sizeof(char) * n);
    }
    

    As you can see, it accepts char ** ptr_string which reads as a pointer which stores the memory location of a pointer which will store the memory address (after the malloc operation) of the first byte of an allocated block of n bytes (right now it has some garbage memory address since it is uninitialized).

    int main(int argc, char *argv[])
    {
      char *toParseStr;
      const int n = 10;
      printf("Garbage: %p\n",toParseStr);
      AllocateString(&toParseStr,n);
      printf("Address of the first element of a contiguous array of %d bytes: %p\n",n,toParseStr);
    
      printf("Enter string here: ");
      scanf("%s",toParseStr);
      printf("%s\n",toParseStr);
      free(toParseStr);
    
      return 0;
    }
    

    Thirdly, it is recommended to free memory you allocate. Even though this is your whole program, and this memory will be deallocated when the program quits, it's still good practice.

    0 讨论(0)
提交回复
热议问题