How to read a sentence of char pointer with scanf()? - c

I have a char pointer: char *sentences; and I read it like this:
#include <stdio.h>
int main() {
char *sentences;
sentences="We test coders. Give us a try?";
printf("%s", sentences);
return 0;
}
but I want to read with scanf() function in c.
scanf("%[^\n]s",S); or scanf("%s",S); didn't work.
How can I do that?

Are you declaring the variable char *sentences; and immediately trying to write to it with scanf? That's not going to work.
Unless a char * pointer is pointing to an existing string, or to memory allocated with malloc-family functions, assigning to it with scanf or similar is undefined behavior:
char *sentences;
scanf("%s", sentences); // sentences is a dangling pointer - UB
Since you haven't actually shared your code that uses scanf and doesn't work, I can only assume that's the problem.
If you want to assign a user-supplied value to a string, what you can do is declare it as an array of fixed length and then read it with a suitable input function. scanf will work if used correctly, but fgets is simpler:
char sentence[200];
fgets(sentence, 200, stdin);
// (User inputs "We test coders. Give us a try")
printf("%s", sentence);
// Output: We test coders. Give us a try.
Also, never, ever use gets.

Related

Segmentation fault on printf or scanf [duplicate]

This question already has answers here:
Returning an array using C
(8 answers)
Closed 2 years ago.
I have a code and can't figure out why it's crashing (segmentation fault) I know from past posts that it has something to do with unaccessable memory (I think), but I initialized my "input" variable.
#include <stdio.h>
#include <stdlib.h>
char *getInfo() {
char input[1000];
scanf("%s", input);
return input;
}
int main() {
char *x;
x = getInfo();
printf("%s\n", x);
return 0;
}
When I run and backtrace the program inside gdb, it says (among other things) "... in main () at error.c:11"
When I break at line 11 after giving input ("bark") try to print the variables, print input gives me '\000 x29' and print x gives me 0x0. I know that 0x0 means that it's null, and I think \000 also means null, but I don't get why., when I scaf'ed input, shouldn't the null be replaced?
Your function getInfo returns the address of the local variable input. But this variable is deleted when the function returns, so the pointer is becoming invalid. The regular way to solve this is by passing the array into the function as a parameter.
char *getInfo(char *input) {
scanf("%s", input);
return input;
}
and on the caller side:
char input[1000];
char *x = getInfo(input);
Of course in your case I would just move the call to scanf into main:
char input[1000];
scanf("%s", input);
printf("%s\n", input);
Please also note that your call to scanf is not safe as scanf might read more input than the buffer can hold. Also my very simple change for getInfo has the disadvantage that you do not pass the length. Normally you should pass the pointer to the buffer and the size of the buffer. That way you can make sure that the function does not overflow the buffer.
For safer variants in your case you might also consider one of these lines:
scanf("%999s", input);
fgets(input, 1000, stdin);

How to return a string to main function?

I am trying to write code to implement strchr function in c. But, I'm not able to return the string.
I have seen discussions on how to return string but I'm not getting desired output
const char* stchr(const char *,char);
int main()
{
char *string[50],*p;
char ch;
printf("Enter a sentence\n");
gets(string);
printf("Enter the character from which sentence should be printed\n");
scanf("%c",&ch);
p=stchr(string,ch);
printf("\nThe sentence from %c is %s",ch,p);
}
const char* stchr(const char *string,char ch)
{
int i=0,count=0;
while(string[i]!='\0'&&count==0)
{
if(string[i++]==ch)
count++;
}
if(count!=0)
{
char *temp[50];
int size=(strlen(string)-i+1);
strncpy(temp,string+i-1,size);
temp[strlen(temp)+1]='\0';
printf("%s",temp);
return (char*)temp;
}
else
return 0;
}
I should get the output similar to strchr function but output is as follows
Enter a sentence
i love cooking
Enter the character from which sentence should be printed
l
The sentence from l is (null)
There are basically only two real errors in your code, plus one line that, IMHO, should certainly be changed. Here are the errors, with the solutions:
(1) As noted in the comments, the line:
char *string[50],*p;
is declaring string as an array of 50 character pointers, whereas you just want an array of 50 characters. Use this, instead:
char string[50], *p;
(2) There are two problems with the line:
char *temp[50];
First, as noted in (1), your are declaring an array of character pointers, not an array of characters. Second, as this is a locally-defined ('automatic') variable, it will be deleted when the function exits, so your p variable in main will point to some memory that has been deleted. To fix this, you can declare the (local) variable as static, which means it will remain fixed in memory (but see the added footnote on the use of static variables):
static char temp[50];
Lastly, again as mentioned in the comments, you should not be using the gets function, as this is now obsolete (although some compilers still support it). Instead, you should use the fgets function, and use stdin as the 'source file':
fgets(string, 49, stdin);/// gets() has been removed! Here, 2nd argument is max length.
Another minor issue is your use of the strlen and strncpy functions. The former actually returns a value of type size_t (always an unsigned integral type) not int (always signed); the latter uses such a size_t type as its final argument. So, you should have this line, instead of what you currently have:
size_t size = (strlen(string) - i + 1);
Feel free to ask for further clarification and/or explanation.
EDIT: Potential Problem when using the static Solution
As noted in the comments by Basya, the use of static data can cause issues that can be hard to track down when developing programs that have multiple threads: if two different threads try to access the data at the same time, you will get (at best) a "data race" and, more likely, difficult-to-trace unexpected behaviour. A better way, in such circumstances, is to dynamically allocate memory for the variable from the "heap," using the standard malloc function (defined in <stdlib.h> - be sure to #include this header):
char* temp = malloc(50);
If you use this approach, be sure to release the memory when you're done with it, using the free() function. In your example, this would be at the end of main:
free(p);

Char arrays and scanf function in C

I expected to get errors in following code, but I did not. I did not use & sign. Also I am editing array of chars.
#include <stdio.h>
int main()
{
char name[10] ="yasser";
printf("%s\n",name);
// there is no error ,
// trying to edit array of chars,
// also did not use & sign.
scanf("%s",name);
// did not use strcpy function also.
printf("%s\n",name);
return 0;
}
I expected to get errors in following code, but I did not.I did not use & sign.
scanf("%s",name);
That's totally ok as name is already the address of the character array.
It sounds like you have several questions:
calling scanf("%s", name) should have given an error, since %s expects a pointer and name is an array? But as others have explained, when you use an array in an expression like this, what you always get (automatically) is a pointer to the array's first element, just as if you had written scanf("%s", &name[0]).
Having scanf write into name should have given an error, since name was initialized with a string constant? Well, that's how it was initialized, but name really is an array, so you're free to write to it (as long as you don't write more than 10 characters into it, of course). See more on this below.
Characters got copied around, even though you didn't call strcpy? No real surprise, there. Again, scanf just wrote into your array.
Let's take a slightly closer look at what you did write, and what you didn't write.
When you declare and initialize an array of char, it's completely different than when you declare and initialize a pointer to char. When you wrote
char name[10] = "yasser";
what the compiler did for you was sort of as if you had written
char name[10];
strcpy(name, "yasser");
That is, the compiler arranges to initialize the contents of the array with the characters from the string constant, but what you get is an ordinary, writable array (not an unwritable, constant string constant).
If, on the other hand, you had written
char *namep = "yasser";
scanf("%s", namep);
you would have gotten the problems you expected. In this case, namep is a pointer, not an array. It's initialized to point to the string constant "yasser", which is not writable. When scanf tried to write to this memory, you probably would have gotten an error.
When you pass arrays to functions in C, they decay to pointers to the first item.
Therefore for:
char name[] ="yasser";
scanf("%s", name) is the same as scanf("%s", &name[0]) and either of those invocations should send shivers down your spine, because unless you control what's on your stdin (which you usually don't), you're reading a potentially very long string into a limited buffer, which is a segmentation fault waiting to happen (or worse, undefined behavior).
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp) {
char *myName = (char *) calloc(10, sizeof(char));
*(myName)='K'; *(myName+1)='h'; *(myName+2)='a'; *(myName+3)='l'; *(myName+4)='i'; *(myName+5)='d';
printf("%s\n",myName);
scanf("%s",myName);
printf("%s\n",myName);
return (EXIT_SUCCESS);
}
#include <stdio.h>
#include <string.h>
int main()//fonction principale
{
char name[10] ="yasser";
int longeur=0;
printf("%s\n",name);
scanf("%s",name);
longeur = strlen(name);
for (int i=0;i<longeur;i++) {
printf("%c",*(name+i));
}
return 0;}

fgets() function doesn't work

I want to calculate length of string and copy the string to another without using c library function, but when I use fgets() function to read the string from keyboard, the code not showing the actual value of length as well as the destination string. I use the fgets() function instead of gets() because the compiler says that gets()function is "deprecated".but when I change sizeof(source) in the code to an integer value suppose 50 the code works fine. Can anybody tell me what wrong with this code and why on earth the compiler say that gets() function is deprecated.
This is the code:
#include <stdio.h>
#include <stdlib.h>
int len(char *source);
char *coppy(char *dest,char *source);
int main (void){
char *source,*dest;
source=(char *)malloc(len(source)+1);
printf("enter string:");
fgets(source,sizeof(source),stdin);
if(source[len(source)-1]=='\n'){
source[len(source)-1]='\0';
}
dest=(char *)malloc(len(source)+1);
coppy(dest,source);
printf("dest=%s\n",dest);
printf("length source=%d\n",len(source));
printf("length dest=%d\n",len(dest));
return 0;
}
int len(char *source){
int i=0;
while(*source!='\0'){
source++;
i++;
}
return i;
}
char *coppy(char *dest,char *source){
while(*source!='\0'){
*dest=*source;
source++;
dest++;
}
*dest='\0';
return dest;
}
This is the result when run that code:
enter string:programming
dest=pro
length source=3
length dest=3
Here is your first mistake:
source=(char *)malloc(len(source)+1)
You pass source to the function len before you initialized it, which is undefined behaviour. From hereon in, anything could happen.
The second mistake is your use of fgets:
fgets(source,sizeof(source),stdin);
The second argument to fgets is supposed to be how many characters are available to be written in, not sizeof(source). Read the documentation for fgets, and sizeof if necessary.
Your error is in how you allocate memory for source
source=(char *)malloc(len(source)+1);
What did you expect len(source) to be? Play computer and run through your len function. I'm surprised your code compiles and runs at all. Your len function on an uninitialized char* should be undefined behavior.
That is why your code fails, you are not allocating enough memory to hold your input string.

What's the cause of my segmentation fault?

I'm trying to write a program that reads in entries from a file into a dynamically allocated array of structures using input redirection. My program compiles fine but I'm getting a segmentation fault and I'm having trouble finding the cause.
Here's my Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct StudentData
{
char* name;
char* major;
double gpa;
} Student;
int main()
{
Student* data = (Student*)malloc(sizeof(Student)*5);
int i;
for(i = 0; i < 5; i++)
{
// allocate memory for name and read input
data[i].name = malloc(50);
*(data+i)->name == scanf("%s", (char*)&data[i].name);
// allocate memory for major and read input
data[i].major = malloc(30);
*(data+i)->major == scanf("%s", (char*)&data[i].major);
// read input for gpa
(data+i)->gpa == scanf("%lf", &data[i].gpa);
//print array
printf("%s\n%s\n%f\n", data[i].name, data[i].major, data[i].gpa);
}
}
Any clues? If it seems obvious it's because I'm relatively new to C!
This line:
*(data+i)->name == scanf("%s", (char*)&data[i].name);
Ignoring the weird and void == for a moment, &data[i].name is wrong since you're taking an address of a pointer. data[i].name would be sufficient here, since the name field is already an address scanf can write into.
And the cast to (char*) is what probably shuts the compiler up about it - did you enter it for this purpose :-) ? Because &data[i].name has the type char**, which scanf wouldn't accept, unless you forcefully casted it to char*.
As a general advice, try to avoid scanf - it leads to very unsafe code (as you've just seen!) Instead, use fgets to read a line (from the standard input too) and then break this line into its constituents. This may initially take a bit more code to implement, but leads to much safer and more predictable code.
*(data+i)->name == scanf("%s", (char*)&data[i].name);
What are you comparing the return value of scanf for? Just remove the first part. Also, data[i].name is already a pointer, so you shouldn't take the address once again. It should just be:
scanf("%s", data[i].name); // no & because name is already a pointer
And similarly:
scanf("%s", data[i].major);
scanf("%lf", &data[i].gpa); // & here because gpa is just a double
There is some unnecessary code being used with scanf, like *(data+i)->name ==. That doesn't do anything useful (and is probably causing the segfault). If it weren't causing access errors, it would compare the return value of scanf with the pointer and then ignore the result of the comparison. (A decent compiler would have warned about this.)
After getting rid of the excess code, it will be technically okay, except there is nothing to prevent buffer overrun. That's done either by controlling the input data, or adding limits to the lengths of the strings, like with scanf("%50s", data[i].name);
&data[i].name and &data[i].major are of type char **, so you cannot safely cast it to char *.
Losing the ampersand will correct your error.
There are also other logical errors with the use of scanf(), but that's probably overwhelming - it'd be nice if you revisited this code once you entered a name of more than 50 characters.

Resources