2

I'm facing an issue connected with printing one char from string in c. The function takes from users two variables - number (number which should print character from string) and string. When I put as a string "Martin" and number is 5 then the output is "i". But when the number is larger than the string length something goes wrong and I actually don't know what's wrong.

PS. If the number is longer than string size it should print "Nothing".

void printLetter() {

    char * string = (char*)malloc(sizeof(char));
    int n;

    printf("Number:\n");
    scanf("%i", &n);
    printf("String:\n");
    scanf("%s", string);

    if(n > strlen(string)) {
        printf("nothing");
    } else {
        printf("%c\n", string[n+1]);
    }

    free(string);


} 
gsamaras
  • 71,951
  • 46
  • 188
  • 305
Martin
  • 1,259
  • 3
  • 17
  • 36
  • 10
    `char * string = malloc(sizeof(char));` you are allocating space for a single `char` - so if you try to write more than that (in `scanf("%s", string);`) you already get *undefined behavior* – UnholySheep Jun 20 '17 at 20:40
  • So i should allocate it like that: `char * string = malloc(100* sizeof(char));` ? – Martin Jun 20 '17 at 20:41
  • @UnholySheep how about `scanf("%0s", string);` or `scanf("%*s", string);` that would be safe if `string[0]='\0';` is called first :) – Jean-François Fabre Jun 20 '17 at 20:41
  • 1
    Yes, you need to allocate more - 100 should be enough. Also note that in this particular code you don't actually need to use `malloc` and `free`, you could just declare a `char` array (e.g.: `char string[100];`) – UnholySheep Jun 20 '17 at 20:44
  • 2
    string[n+1]-->string[n-1]...also you have allocated only 1 byte for string variable. – Pushan Gupta Jun 20 '17 at 20:45
  • Yeah Vidor you've saved me. – Martin Jun 20 '17 at 20:46
  • You may not know the dangers of `scanf`. If you don't, I suggest you read this: http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html – nounoursnoir Jun 20 '17 at 20:51
  • Yea, but I do it only for exams. I do not plan to be C programmer. – Martin Jun 20 '17 at 20:53
  • Don't you want n-1? It is zero based index. So position 5 is actually index 4. – Andrew Truckle Jun 21 '17 at 16:07

3 Answers3

5

There is no need for dynamic allocation here, since you do not know the length of the string in advance, so just do:

void printLetter() {
    char string[100]; // example size 100
    ...
    scanf("%99s", string); // read no more than your array can hold
}

A fun exercise would be to count the length of the string, allocate dynamically exactly as mush space as you need (+1 for the null terminator), copy string to that dynamically allocated space, use it as you wish, and then free it.


Moreover this:

printf("%c\n", string[n+1]);

should be written as this:

printf("%c\n", string[n-1]);

since you do not want to go out bounds of your array (and cause Undefined Behavior), or print two characters next of the requested character, since when I ask for the 1st character, you should print string[0], when I ask for the 2nd, you should print string[1], and so on. So you see why we need to print string[n-1], when the user asks for the n-th letter.

By the way, it's common to use a variable named i, and not n as in your case, when dealing with an index. ;)


In your code, this:

char * string = malloc(sizeof(char));

allocates memory for just one character, which is no good, since even if the string had one letter only, where would you put the null terminator? You know that strings in C should (almost) always be NULL terminated.

In order to allocate dynamically memory for a string of size N, you should do:

char * string = malloc((N + 1) * sizeof(char));

where you allocate space for N characters, plus 1 for the NULL terminator.

BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
gsamaras
  • 71,951
  • 46
  • 188
  • 305
1

Couple of problems...

sizeof(char) is generally 1 byte. Hence malloc() is allocating only one byte of memory to string. Perhaps a larger block of memory is required? "Martin", for example, will require at least 6 bytes, plus the string termination character (seven bytes total).

printf("%c\n", string[n+1]) is perhaps not quite right...

  String: Martin\0
  strlen= 6
  Offset: 0123456
  n = 5... [n+1] = 6
  The character being output is the string terminator '\0' at index 6.

This might work better:

  void printLetter() {

      char * string = malloc(100 * sizeof(char));
      int n;

      printf("Number:\n");
      scanf("%i", &n);
      printf("String:\n");
      scanf("%s", string);

      if(n > strlen(string)) {
          printf("nothing");
      } else {
          printf("%c\n", string[n-1]);
      }

   free(string);


  }
Mahonri Moriancumer
  • 5,993
  • 2
  • 18
  • 28
  • Why using malloc if you can just declare char string[100]; ? What will happen when string is more than 100 characters long? – DevilaN Jun 20 '17 at 20:56
  • 1
    @DevilaN, There are many things I would do to bring this code up to my standards. Unfortunately, by then, there would be little resemblance to the question code. I think it is best to make minimal changes, sufficient to get the code operational without getting into the problems of scant(), buffer sizes, etc. – Mahonri Moriancumer Jun 20 '17 at 21:00
  • Detail: "sizeof(char) is generally 1 byte." In C, it is always 1 byte, as C defined a _byte_ – chux - Reinstate Monica Jun 20 '17 at 21:38
-1

You are facing buffer overflow. Take a look to this question, so it will show you how to manage your memory properly in such situation: How to prevent scanf causing a buffer overflow in C?

Alternatively you can ask for number of letter and allocate only that much memory + 1. Then fgets(string, n,stdin); because you don't need rest of the string :-)

DevilaN
  • 1,317
  • 10
  • 21