Enter a string into a struct: segmentation fault - c

So far I've been able to answer all all my questions by a dutiful search, but this one has me stumped.
So. I've reduced this code to the minimum necessary to produce the error. Here it is:
#include <studio.h>
struct string {
char *data;
} s;
int main(int argc, char *argv[])
{
printf("Enter a string. ");
scanf("%s\n", &s.data);
printf("%s", s.data);
return 0;
}
I'm using gcc 4.6.3 and compiling with -Wall -g using classic defensive programming tactics.
I posted this from my phone, so there may be typos and autocorrect madness.

When using scanf, to read as a string using an unallocated pointer, specify the 'm' directive forcing scanf to allocate memory as needed while skipping newline. You are responsible for freeing the memory allocated to the string. scanf expects the pointer provided to be type char**.
scanf ("%m[^\n]%*c", &s.data);
The trailing %*c reads and discards the trailing newline. (be aware of this if you simply press [enter])

Point 1. allocate memeory to the pointer before using it
s.data = calloc(DATASIZE, sizeof (char));
Recommended Alternative: malloc()
Point 2. Use scanf() to take the input and store it.
scanf("%s", s.data);
Recommended Alternative: fgets()
Please find below is a corrected version of your code.
#include <stdio.h>
#include <stdlib.h>
#define DATASIZE 128
struct string {
char *data;
} s;
int main(int argc, char *argv[])
{
s.data = calloc(DATASIZE, sizeof (char));
printf("Enter a string. \n");
scanf("%s", s.data);
printf("Input is : %s\n", s.data);
return 0;
}

You need allocated the memory by using malloc first.
s.data = malloc(100);

The fact that it's in a struct isn't the problem. The problem is that the pointer data is not initialized, and there's no memory for the stuff to be copied into.
This solves the problem:
struct string
{
char data [SOMEBIGNUMBER]
} s;
and so does this: keep string as it is, but allocate the space for data in main using malloc.

It seems that in this statement
("%s", s.data);
there is a typo. I think you mean
scanf("%s", s.data);
Otherwise
("%s", s.data);
is an expression with the comma operator that simply returns s.data.
The first problem with your code that you have to allocate memory where you are going to write enetered data.
For example
s.data = malloc( 256 * sizeof( char ) );
Instead of 256 you may use nay value as you like.
The second problem is that you should use fgets instead of scanf because using the last is unsafe.
So the main can look like
int main( void )
{
const size_t N = 256;
s.data = malloc( N * sizeof( char ) );
s.data[0] = '\0';
printf("Enter a string (no more than %zu characters). ", N );
fgets( s.data, N, stdin );
printf("%s\n", s.data);
free( s.data );
return 0;
}
Also you may remove the new line character that will be stored in data.s after fgets.
For example
size_t len = strlen( s.data );
if ( len && s.data[len - 1] == '\n' ) s.data[len - 1] = '\0';

In this use malloc for memory allocation of structure object and char pointer.
below is corrected code....
#include <stdio.h>
#include <malloc.h>
struct string {
char *data;
} *s;
int main(int argc, char *argv[])
{
s = (struct string*)malloc(sizeof(struct string));
s->data = (char*)malloc(sizeof(char) * 100);
printf("Enter a string : ");
scanf("%s", s->data);
printf("%s\n", s->data);
return 0;
}

Related

can not get dynamic string allocation to work

hey guys i have looked around for a solution and tried everything i can think of im new to pointers and dynamic strings and i could really do with some help with problem. im currently learning c and i need to get the user to input a dynamic size for the string length . i need to make it so the users input can not be bigger then 100 . here's where i am at currently . i have the code booting but if i try set the size to let's say 5 i can still input way more chars into the string. cheers really appreciate any help .
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
int maxSize = 100;
char *name = (char*) malloc (maxSize * sizeof (char));
int n;
char text1[]= ("input string size\n");
printf ("your string lenght is %d\n", strlen(name));
//getting size
n=intPrintScanner(text1);
printf ("your size is %d\n",n);
name = realloc (name, sizeof (char) * n);
//printing results
printf ("your string lenght is %d\n",strlen (name));
scanf("%s", name);
printf("your string is %s",name);
free(name);
fflush(stdin);
printf("press any key to close");
getchar();
return (0);
}
Bugs:
You never assign any data to name so it just contains garbage. You can't use strlen on it before you have stored valid data there either. You can store a string inside name by for example using strcpy.
When using realloc, there's no guarantee that the old pointer is the same as the returned pointer. Also, you need error handling. Implement it like this instead:
char* tmp = realloc (name, n);
if(tmp == NULL)
{
/* actual error handling here in case realloc fails */ }
}
name = tmp; // assign pointer to the new area only if allocation succeeded
fflush(stdin); is not well-defined, never use fflush on input streams. Instead you should discard unwanted line feed characters from stdin - which could be as trivial as an extra getchar() call just after reading something. Check out How to read / parse input in C? The FAQ for lots of general good advise regarding how to take input from stdin.
Cosmetic/style:
No need for parenthesis here: char text1[]= ("input string size\n");. All it achieves it to make the code look strange.
The correct form of main is int main (void). The int main() is obsolete style.
There is no need to wrap the expression passed to return in a parenthesis.
There is never a need to multiply something with sizeof (char), since sizeof (char) is by definition always 1 no matter system.
There is no need to cast the result of malloc.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
char* read_until(int fd, char end) {
int i = 0, size;
char c = '\0';
char* string = (char*)malloc(sizeof(char));
while (1) {
size = read(fd, &c, sizeof(char));
if (c != end && size > 0) {
string = (char*)realloc(string, sizeof(char) * (i + 2));
string[i++] = c;
} else {
break;
}
}
string[i] = '\0';
return string;
}
int main()
{
char *name;
int correct=0;
do{
write(1,"Put a name: ",strlen("Put a name: "));
name = read_until(STDIN_FILENO,'\n');
if(strlen(name) > 99){
write(1,"Error\n",strlen("Error\n"));
}else{
correct=1;
}
}while(correct != 1);
write(1,name,strlen(name));
free(name);
}
Try using write and read instead of printf and scanf, it is better for allocating dynamic memory, read and try to understand the read_until function, there are better ways to do main.

getting segementaion fault when I declare Pointer to the string(Didn't try to modify it)

I am getting segmentaion fault when I Try to declare Pointer to the string like this char *b = "This is String"; to check why sizeof() is always returning 8 but when I remove this line everything works great!!
here is My main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
char *b = "how are you";
printf("Enter the string:- ");
for(int i =0;1;i++)
{
s = (char*)realloc(s,i+1);
s[i]=getchar();
if(s[i] == '\n')
{
s[i]= '\0';
break;
}
}
printf("Your String:- %s \nAnd It's length:- %lu\nAnd the Size:- %lu",s,(strlen(s)),sizeof(s));
printf(" \nThe size of b is %lu",(sizeof(b)));
}
If I remove the line char *b = "how are you"; and printf(" \nThe size of b is %lu",(sizeof(b))); the program runs fine like this:-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
//char *b = "how are you";
printf("Enter the string:- ");
for(int i =0;1;i++)
{
s = (char*)realloc(s,i+1);
s[i]=getchar();
if(s[i] == '\n')
{
s[i]= '\0';
break;
}
}
printf("Your String:- %s \nAnd It's length:- %lu\nAnd the Size:- %lu",s,(strlen(s)),sizeof(s));
//printf(" \nThe size of b is %lu",(sizeof(b)));
}
OutPut
Enter the string:- I am Using Eclipse in Linux mint
Your String:- I am Using Eclipse in Linux mint
And It's length:- 32
And the Size:- 8
Why I can't Declare the string char *b = "how are you";
the issue is that char *s; doesn't initialize s
So the first time you enter in realloc, you pass it an invalid pointer: undefined behaviour.
char *s = NULL;
is more like it.
char *b; -> This means that b is a character pointer. It is only capable of addressing a string which has already been declared. Meaning it cannot hold the string as a whole. It should be initialized with the base address of an already existing string or can hold the address of a dynamically allocated string. Therefore,
char *b = "how are you"; //is what causing you the problem.
Instead, you could try:
char b[] = "how are you"; //which should work fine!
Cheers!
The posted code is exhibiting several problems:
the pointer: s is not initialized. Passing an uninitialized pointer to realloc() results in undefined behavior and can lead to a seg fault event.
the correct signature for main(), when the parameters are not going to be used is:
int main( void )
variables passed to realloc() should be size_t, not int.
when calling realloc(), assign the result to a temp variable then check that variable for NULL. If NULL, then cleanup and exit.
the function: getchar() returns a int, not a char.
Never trust the user to do the expected thing, so also check if the returned value from getchar() is EOF.
the expression: sizeof( s ) or sizeof( b ) will return the sizeof a pointer (4 or 8 depending on the underlying architecture and certain compile parameters.
There are a number of 'implicit' conversions of data types in the posted code. Such implicit conversions can cause problems. Best to eliminate such implicit conversions.
the posted code leaks memory.
In the following proposed code:
the reason for each header file being included is documented
all the known problems with the code are corrected
proper checking for errors is implemented
each line that was changed or added is commented via //<<--
Note: when compiling, always enable the warnings, then fix those warnings. (for gcc, suggest:
gcc -Wall -Wextra -pedantic -Wconversion -std=gnu11 mysource.c -o mysource
And now, the proposed code:
#include <stdio.h> // getchar(), perror()
#include <stdlib.h> // realloc(), free(), exit(), EXIT_FAILURE
#include <string.h> // strlen()
int main( void )
{
char *s = NULL; //<<-- initialized
char *b = "how are you";
printf("Enter the string:- ");
for( size_t i =0; 1; i++ ) //<<-- need 'size_t' for 'realloc()'
{
char *temp = realloc( s, i+1 ); //<<-- proper way to call 'realloc()'
if( !temp ) // <<-- checking for failure and handling failure
{
perror( "realloc failed" );
free( s );
exit( EXIT_FAILURE );
}
s = temp;
int k = getchar(); //<<-- returns 'int', not 'char'
if( k == EOF || k == '\n' ) //<<-- a user can do almost anything
{
s[i]= '\0';
break;
}
else //<<-- input 'good' so update array
{
s[i] = (char)k;
}
}
// terminate format strings with '\n'
// so data is immediately displayed
// honor the right edge of a printed page (~column 80)
// when listing the program
printf("Your String:- %s \nAnd It's length:- %lu\nAnd the Size:- %lu\n",
s,
(strlen(s)),
sizeof(s)); // <<-- yields the size of a pointer
printf(" \nThe size of b is %lu\n",
(sizeof(b))); // <<-- yields the size of a pointer
}
In addition to the fact that you never initially allocated s, sizeof(b) == sizeof(char*), not the length of the string.

Is there a possible way to use char in strcmp?

I have this program that's supposed to be a 'chat simulator', the only thing it's supposed to do now is replying 'Hello!' when the user types 'Hello'.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <string.h>
int main()
{
printf("Chat simulator!\n");
do {
char x;
printf("[User1] ");
scanf("%s",&x);
if (strcmp (x,"Hello") == 0)
{
Sleep(1500);
printf("[User2] Hello!\n");
}
else {}
} while(1);
}
I know that strcmp is only for const char *, not a single char, and that's the problem here, but I couldn't find any other solution for this, since I need to use char x in scanf, so it can't be a const char *. Also it may be possible that I'm using strcmp wrong.
Code:Blocks warning:
passing argument 1 of 'strcmp' makes pointer from integer without a cast*
expected 'const char *' but argument is of type 'char'*
Edit:
So I changed the char to char[16] as #robin.koch told me, and it's all working as it should. Thanks!
You cannot compare a string with a char with strcmp, but it is easy to do by hand:
int samechar(const char *str, char c) {
return *str == c && (c == '\0' || str[1] == '\0');
}
The above function however is not what you need for you problem:
You should read a string from the user, not a single char.
scanf() needs a pointer to a char array for the conversion specifier %s.
Furthermore you should specify the maximum number of characters to store into the this array to avoid potential a buffer overflow.
Finally, scanf() will only read a single word. You probably want to read a full line from the user. Use fgets() for this.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main(void) {
printf("Chat simulator!\n");
for (;;) {
char buf[100];
printf("[User1] ");
if (!fgets(buf, sizeof buf, stdin))
break;
buf[strcspn(buf, "\n")] = '\0'; /* strip the newline if present */
if (strcmp(buf, "Hello") == 0) {
printf("[User2] Hello!\n");
}
}
return 0;
}
As others have pointed out, you're trying to store a string into a char variable using scanf when chars are only meant to store one character. You should you use a char * or char[] variable to hold your string instead. So change
char x;
printf("[User1] ");
scanf("%s",&x);
//...rest of your code...
to
char * x = malloc(sizeof(char) * 10); //can hold up to ten characters
printf("[User1] ");
scanf("%s",x);
//...rest of your code...
free(x);
Note that if you just want to use a char array instead of a pointer you can replace the first line above with something like char x[10]; and get rid of free(x);

Beginner in C: strings and memory

So this course I'm doing wants us to play around with memory management and pointers. I'm not really fully understanding them.
I keep getting a error:
Segmentation fault (Core dumped)
Apparently I don't have access to memory?
It's something wrong in my slen function?
/*
In these exercises, you will need to write a series of C functions. Where possible, these functions should be reusable (not use global variables or fixed sized buffers) and robust (they should not behave badly under bad input eg empty, null pointers) .
As well as writing the functions themselves, you must write small programs to test those functions.
- Remember, in C, strings are sequences of characters stored in arrays AND the character sequence is delimited with '\0' (character value 0).
----------------------------------------------------
1) int slen(const char* str)
which returns the length of string str [slen must not call strlen - directly or indirectly]
*/
#include <stdio.h>
#include <stdlib.h>
/* Returns the length of a given string */
int slen(const char* str) {
int size = 0;
while(str[size] != '\0') {
size++;
}
return size;
}
/*
2) char* copystring(const char* str)
which returns a copy of the string str. [copystring must not call any variant of strcpy or strdup - directly or indirectly]*/
char* copystring(const char* str) {
int size = slen(str);
char *copy = (char*) malloc (sizeof(char) * (size + 1));
copy[size] = '\0';
printf("before loop");
int i = 0;
while (*str != '0') {
copy[i++] = *str++;
}
return copy;
}
int main() {
char *msg = NULL;
printf("Enter a string: ");
scanf("%s", &msg);
int size = slen(msg);
//printf("The length of this message is %d.", size);
// printf("Duplicate is %s.", copystring(msg));
// Reading from file
}
The problem isn't in your slen function, it happens before that when you're using scanf:
you need to make some space for the string that you're reading from the user using scanf
you don't need to pass the address of your memory buffer to scanf, the variable is already holding an address.
Amended code:
char msg[101];
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
Alternately, if you're being asked to learn about memory allocation, study the usage of malloc:
char *msg = malloc(101);
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
While learning about malloc, don't forget to also study up on the associated usage of free.
Also important and significant here is the management of your buffer size: when you make memory for the string that you'll be scanning from the user, you should put a limit on the amount of string that you actually read. There are a few ways to do this: start by studying the scanf format string, where you can use:
scanf("%100s", msg);
You need to assign memory to msg in your main
Either use char msg[10] or use malloc.
char *msg = malloc(10*sizeof(char))

fgets segmentation fault when reading input from user

here's the offending code using ubuntu
char *name;
int main(void)
{
fgets(name, sizeof(name), stdin);
}
void HUD()
{
printf("%s ", name);
}
Here's my problem. I started with scanf("%s", &name) and was getting junk at the end of the string. Through the last 2 hours have been reading docs on scanf, and fgets, because apparently scanf shouldn't be used when you don't know the size of the array you want, (and since user input can vary in size) I decided to try using fgets. I've also tried setting a fixed value both by char name[100]; and by fgets(name, 100, stdin)
Now I'm getting a segmentation fault, and through reading every result I found on the first 2 pages of google, my syntax appears correct, and I've found nothing on cboard or here to fix my problem.
Any ideas?
sizeof(name) Will be the size of the pointer on your system, on mine it's 8 bytes. Not the size of the buffer, as you might have been expecting
Also char* name is uninitialised. You will try to write to an uninitialised buffer and it will end in undefined behaviour.
To resolve either make it a fixed size buffer or allocate some space on the heap.
Allocate
#include <stdio.h>
#include <stdlib.h>
#define NAME_SIZE 100
char *name;
void HUD()
{
printf("%s ", name);
}
int main(void)
{
name=calloc(NAME_SIZE, sizeof(char));
fgets(name, NAME_SIZE, stdin);
HUD();
free(name);
}
Static Array
#include <stdio.h>
#include <stdlib.h>
#define NAME_SIZE 100
char name[NAME_SIZE];
void HUD()
{
printf("%s ", name);
}
int main(void)
{
fgets(name, NAME_SIZE, stdin);
HUD();
}
You must pass the size of the buffer to fgets so it know how much space it has to write in to.
char *fgets(char *restrict s, int n, FILE *restrict stream);
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a is read and
transferred to s, or an end-of-file condition is encountered. The
string is then terminated with a null byte. [0]
You need to allocate it to a specific size and call fgets with that size. This code can help you accomplish the same thing, but it has a fixed size buffer.
#include <stdlib.h>
#include <stdio.h>
char name;
char* buffer;
int buffer_size = 16;
int i = 0;
void HUD()
{
printf("%s ", buffer);
}
int main(void)
{
buffer = malloc(buffer_size);
if(!buffer) return;
for(;;) {
name = getchar();
if(name < 0) {
buffer[i] = '\0';
goto finish;
} else if(i < (buffer_size -1)) {
buffer[i++] = name;
} else if(name == '\n') {
break;
}
}
buffer[i] = '\0';
finish:
HUD();
free(buffer);
return 0;
}
[0] http://pubs.opengroup.org/onlinepubs/009695399/functions/fgets.html

Resources