2

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.

  • 1
    You haven't initialised the pointer. Also, 2nd line is wrong. without scanf. That's why you are reading null. – ha9u63a7 Nov 20 '14 at 08:49
  • 2
    It's `#include `... Please post your actual code! – urzeit Nov 20 '14 at 08:50
  • 1
    (That is, minimal code -- but code that is as right -- and compileable -- as you can make it.) – Topological Sort Nov 20 '14 at 08:52
  • Like I said, my eyes are tired. I'm pretty fried. Yeah, that WAS scanf(%s... IPhone "fixed" that for me. Sorry. Just assume my code is correct. Circa 1997? What's the fix? – Richard G. Crockett Nov 20 '14 at 09:00
  • Still, problem is there. – Sourav Ghosh Nov 20 '14 at 09:11
  • Sorry, but I'm am brand new to this forum. Even my comments are truncated due to my big, thick fingers hitting wrong buttons. The code is now edited. Thanks for seeing the most egregious errors in my typing! – Richard G. Crockett Nov 20 '14 at 09:23
  • I deeply apologize for my typos. It's hard enough to post here from a mobile device. Sorry to frack you up with a noise to signal ratio out of bounds. Thanks for the input. It's really great that I even got answers. – Richard G. Crockett Nov 20 '14 at 10:01
  • @RichardG.Crockett, I just edited your code again. I think this is the way it really is, assuming the `printf` was correct as it was, just the `scanf` was missing. If I was wrong with it, please complain. – glglgl Nov 20 '14 at 10:28
  • No. You got it. Thanks for grokking what I was trying to say – Richard G. Crockett Nov 20 '14 at 11:15

6 Answers6

2

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])

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Hooah! Yep. That worked! Super! But I feel like a script kiddie just copying and pasting. How do I research the %m parameter? I can't even find any reference to that. This is total news to me. My background is in Perl. Getting under the hood is both the joy and pain of C. Most peculiarly, why is is it that code that worked before now doesn't? – Richard G. Crockett Nov 20 '14 at 09:48
  • That is the beauty of C. It is an exact language where there is no `almost` right syntax. This is how C is able to give low level access to the hardware. Every statement and every subpart of a statement have to be right. Any additional time spent digging in the details in C is time well spent. This little gem for `scanf` can be found in `man scanf` (but it isn't near the top :) Glad I could help. – David C. Rankin Nov 20 '14 at 10:06
  • Well, I surely missed that, so thanks. Time to delve deeply into "man 3 scanf". Meanwhile, up vote me so I have enough karma to at least thank the people who put up awesome answers. – Richard G. Crockett Nov 20 '14 at 10:20
  • Done, you have the karma now :) – David C. Rankin Nov 20 '14 at 10:45
  • Well, I'm not finding that in my implementation. I'm getting that this is some serious guru s**t. On the one hand, I'm going, "Hmm, no wonder it's not obvious, on the other, I'm going, "Well, it should be because this is wicked cool and super important." And thanks for the up vote! – Richard G. Crockett Nov 20 '14 at 10:53
  • Well, after not finding that on my probably outdated ubuntu implementation, I went to our 900 pound gorilla friend, aka, "google." Uh Huh. So %m is an awesome form of dynamic malloc. Stupendous. Thanks. – Richard G. Crockett Nov 20 '14 at 12:04
1

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;
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • As scanf is supposed to write to the places where data is expected, there is no need to prefer `calloc()` over `malloc()`. – glglgl Nov 20 '14 at 08:59
  • @Sourav. I was so busy messing around last night, I never thanked you for your detailed answer. Yes, fgets is probably the way to go. But I got hung up over something that should have worked but didn't. – Richard G. Crockett Nov 20 '14 at 18:32
0

You need allocated the memory by using malloc first.

s.data = malloc(100);

  • malloc has nothing to do with it. He is not reading the string in the first place. – ha9u63a7 Nov 20 '14 at 08:50
  • He uses scanf(), although misspeled – Oren Kishon Nov 20 '14 at 08:51
  • @OrenKishon I don't see any `scanf()` on the question at all. Except, you consider "missing" a special case of "misspelt". – glglgl Nov 20 '14 at 09:00
  • The code without scanf won't cause a seg-fault as reported, so it must have been missed only in the question code. - @glglgl – Oren Kishon Nov 20 '14 at 09:06
  • @OrenKishon A `printf("%s", s.data);` with `s.data` mis-initialized will surely segfault. (No, not surely, but probably.) But, as we see, it really was only missing in the Q. – glglgl Nov 20 '14 at 10:29
0

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.

Topological Sort
  • 2,733
  • 2
  • 27
  • 54
  • Whoa. I'm kinda blown away by all this instant data. You cats are the bomb. But I need to check. Sorry for the typos. Here I am trying to talk and then suddenly, Yah! I'm on REI's website. Seriously. – Richard G. Crockett Nov 20 '14 at 09:17
0

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';
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
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;
}
Amol
  • 69
  • 2
  • 11