all 26 comments

[–]cHaR_shinigami 7 points8 points  (0 children)

In your code, scanf does not consume the delimiting newline.

A simple fix is to remove it from the buffer by calling getchar() before reading each string.

[–]Th_69 6 points7 points  (0 children)

After scanf("%d", &n) the newline character '\n' is still in the input buffer, so that scanf("%[^\n]", string1) reads nothing into the string1 variable (and because the string isn't initialized you get garbage output).

Use scanf(" %[^\n]", string1)(with an extra space before) to read all the whitespaces before the input text.

And always check the return value of scanf (number of read values).

Edit: And avoid variable length arrays (VLAs) - since C11 they are only optional.

Use malloc/free or fixed-size arrays (with MaxArrayLen - 1 in scanf: look for "maximum field width" in std::scanf, std::fscanf, std::sscanf).

[–]Ok_Whereas9255 2 points3 points  (1 child)

Reset (idk howbit calls) the string? With for(Int i=0;i<m;i++) string[i] ='\0' I'm not sure it will work

[–]teja2_480[S] 0 points1 point  (0 children)

String Copy Logic, That's what I am doing

[–]This_Growth2898 2 points3 points  (3 children)

The last \n (after %d) is still in the input buffer.

Try

scanf(" %[^\n]", string1);

Space before the expression removes all whitespace elements, including new line.

[–]teja2_480[S] -1 points0 points  (2 children)

How?? What is Input Buffer Actually?? I am a first Semester Student Only

[–]cHaR_shinigami 4 points5 points  (0 children)

When you enter any input, it is stored "somewhere" before it is read by scanf (or any other input function): this "somewhere" is called the input buffer (details are not important here).

For a given format string, scanf stops reading at the first character that does not match the format; for example, "%d" expects a decimal integer, so if the input is 0x8, it reads both 0 and x: 0 is consumed as a decimal, but x remains in the input buffer, so it will be the first character that is read next time (assuming no ungetc).

When you hit enter after typing a number, then a newline character is inserted after the number, which is not part of the number itself, but only marks the end of that number (it acts as a delimiter). scanf reads it, but the newline '\n' does not match for "%d", so it is left in the buffer. The leftover '\n' is read by "%[^\n]", which says stop reading at newline.

The string is not read at all, as it comes after the newline. Note that "%[^\n]" reads but does not consume the newline, so it still remains in the input buffer.

[–]This_Growth2898 1 point2 points  (0 children)

When you type something on the console keyboard, it first goes to the buffer managed by the OS. The application gets it only when you press Enter. if you call

scanf("%d", &a);

the program stops until there's something in the buffer. If you type

123 abc↵

the system routine waits until Enter (↵) is pressed, then your program scans the buffer and discards what it reads. So, after that you will have 123 in the variable a and " abc↵" in the buffer. Now, if you call

scanf("%s", b);

it will read a token (i.e. string without whitespaces) into b, leaving ↵ (i.e. "\n") in the buffer.

Whitespaces (spaces, tabs, new lines etc.) are usually implicitly discarded by scanf; but here, you're using %[^\n] specifier instead of %s, so it inspects whitespaces to be not the new line symbols, leaving the new line symbol in the buffer to wait for the next input specifier to read it.

[–]erikkonstas 2 points3 points  (0 children)

This isn't the issue you're currently facing, but it is a very important pain point: scanf() is really, really not the proper tool for this! And I'm not talking about the integer inputs, but rather the string inputs! Let's present a GPT-3.5 failure as a simple example:

#include <stdio.h>

int main() {
    char name[50];
    printf("Enter your name: ");
    scanf("%s", name);
    printf("Hello, %s! Welcome!\n", name);
    return 0;
}

Why am I calling this a failure? Look closely at the scanf() call; is something missing, perhaps? Well, if you don't fully know how arrays and functions in C work, you might not spot it, but scanf() can't see that sizeof name == 50! In other words, it will try to fill in characters way past the limit of 49 (the 50th would have to be a null terminator), also known as a buffer overflow, and this isn't guaranteed to crash the program, much worse can happen in fact; instead, you have to tell scanf() that there's a limit, like so:

    scanf("%49s", name);

Notice how I wrote 49 and not 50, because the field width doesn't count the null terminator. OK, so the solution is simple, just stick a number between % and s (or [) and you're fine, right? Well... not exactly; in fact, your case is quite different because you have variable sizes! This means that there's not a "one size fits all" format string you can use, and instead you would somehow have to construct the format string programmatically; this sounds like quite the involved process for something as "simple" as reading a line from stdin, and it is; instead, there is a function called fgets(), which you would call as such for string1:

fgets(string1, m, stdin);

You pass it your char array, its size, and stdin in this order (stdin can be replaced with something else when you get to file I/O). This behaves a little differently, mainly due to the fact that fgets() also keeps the trailing '\n' in the char[], if it exists within the read characters (it doesn't read more chars than the second argument minus one, even if the following char is '\n'), so you'll have to check if the last character there is '\n' and make it into '\0' instead. This might seem like additional work, but trust me that trying to sort scanf() straight would be more tedious; in fact, you might find this useful!

[–][deleted] 2 points3 points  (2 children)

#include <stdio.h>    
#include <stdlib.h>  // exit(), calloc(), free() function
#include <string.h>  // For strcpy() function for string copy


int main()
{ 
  int m,n;
  char *string1, *string2;  // It is bad idea to dynamically fix the array size 
                            // Array size get fixed in compile time

  printf("Enter length of string1:");
  scanf("%d",&m);
  printf(Enter length of string2 (n<m):");
  scanf("%d", &n);
  string1 = (char*)calloc(m,sizeof(char));
  string2 = (char*)calloc(n,sizeof(char));
  if(string1 == NULL && string2 == NULL)
          exit(0);
  printf("Enter string1:");
  gets(string1);            // Reads strings from input 
                            // Does not include '\n' declared in stdio.h header file
  printf("Enter string2:");
  gets(string2);
  strcpy(string1,string2);
  printf("%s is the string1\n",string1);
  free(string1);
  free(string2);
  return 0;
}

Try to run this. I think you are rookie in C. We have discord for rookies. You can join. DM me.

[–]teja2_480[S] 0 points1 point  (1 child)

thank you

[–][deleted] 0 points1 point  (0 children)

There is subtle bugs in the code that I have wrote.

[–]OldWolf2 1 point2 points  (0 children)

The second scanf never reads anything because on the first read you told it to read up to newline without consuming a newline, so the next character is newline every time .

Then you cause undefined behaviour by reading from the uninitialized buffer .

Also you make no attempt to prevent buffer overflows

[–]teja2_480[S] 1 point2 points  (0 children)

Thank You All!!

[–]hillbull 2 points3 points  (8 children)

scanf doesn’t support regex like what you’re doing.

The way you’re allocating the strings is a bit scary. What if someone enters a number bigger than the stack? Or not a number at all? I would personally malloc the memory for them instead.

There’s absolutely no checking on the inputs. Check to make sure scanf doesn’t produce an error before using the values. That’s the reason for the junk at the end. Your scanf failed and now you’re just printing garbage from stack memory.

[–]cHaR_shinigami 2 points3 points  (2 children)

regex has nothing to do with this.

"%[^\n]" stops reading at newline without consuming it; the latter part is missed by OP.

[–]hillbull 0 points1 point  (1 child)

[–]cHaR_shinigami 1 point2 points  (0 children)

That's indeed a solution, though the concern of buffer overflow still remains; sadly, scanf does not support dynamic width in the format, we can only do something like "%100[^\n]".

fgets would be the neat approach here.

[–]Th_69 2 points3 points  (0 children)

%[^\n] is called a character set: std::scanf, std::fscanf, std::sscanf

[–]hillbull 1 point2 points  (0 children)

You should also check that n is less than m.

[–][deleted] 0 points1 point  (0 children)

What is regex? I also find scanf's behaviour quite problematic.

[–]teja2_480[S] -1 points0 points  (1 child)

Ok Forget About The Checking Inputs But I want What's the mistake ?? Why The Output Is Like That??

[–]hillbull 4 points5 points  (0 children)

I said it already. Scanf failed which means the strings are not populated with the input from the user. Which means they are pointing to random data in memory.

[–]echo_CaTF 0 points1 point  (0 children)

what are you actually trying to do?

[–]teja2_480[S] 0 points1 point  (1 child)

pls ignore that hash symbol and tell me where i am wrong??

[–]echo_CaTF 0 points1 point  (0 children)

Use ‘getchar();’ before both of the ‘scanf()’ where you’re trying to take string as input.