简体   繁体   中英

C struct with pointer think I'm not allocating memory correctly

  typedef struct Data* DATAS;

  struct Data {
      char *name;
      char *city;
      DATAS next;
  };
  typedef struct Data DATA;

  int main(void){
     DATAS tmp;

     tmp=(DATAS) malloc(sizeof(DATA));   
     printf("please enter name:\n");
     scanf("%s",&tmp->name);
     printf("%s\n",&tmp->name);
     printf("please enter city:\n");
     scanf("%s",&tmp->city);
     printf("%s\n",&tmp->name);
     printf("%s\n",&tmp->city);

  return 0;
  }

This is part of a homework assignment. Or rather the concept is. I need to use 'typedef struct Data* DATAS;' which is throwing me off. When I run this I overwrite name with part of city so I get this as a result.

please enter name:
name
name
please enter city:
city
namecity
city

Any help would be great. Thanks. I've tried different variants of malloc using

tmp=(DATAS) malloc(sizeof(DATA));
tmp=(DATA) malloc(sizeof(DATA));

The best way to allocate a struct Data is:

struct Data *tmp;
tmp = malloc(sizeof *tmp);
if (tmp == NULL) {
    /* malloc failed, abort or take corrective action */
}

Defining a typedef for a pointer type is not recommended (at least by me); using struct Data * explicitly makes it clearer to the reader that you're dealing with a pointer.

Defining a typedef for a struct type is also unnecessary. A typedef simply declares a new name for an existing type; your type already has a perfectly good name, struct Data . Admittedly you have to type the struct keyword repeatedly, but that's not really a problem.

Casting the result of malloc is unnecessary; malloc returns a void* result, which can be implicitly converted to your pointer type. The cast can hide errors, such as forgetting the required #include <stdlib.h> .

But these are style issues. Your current code:

tmp=(DATAS) malloc(sizeof(DATA));

is ok, and it should work. The problem is later in your code.

scanf with a "%s" format expects a char* argument. You're giving it the *address* of a char* argument. You're giving it the *address* of a char* object, ie, a value of type char** . The compiler won't necessarily warn you about this. So this:

scanf("%s",&tmp->name);

should be:

scanf("%s", tmp->name);

But that's still a problem, since tmp->name is an uninitialized pointer. It probably points to some random location in memory, and the call attempts to store data at that location. Or it could hold an invalid address, causing a crash. The behavior is undefined.

You need to allocate space to hold the name, and cause tmp->name to point to it. You probably need another malloc() call here.

So how much space do you need to allocate? Well, there's no good answer to that, because scanf("%s", ...) places no limit on how many bytes it will read. However big the allocated space is, you can overflow it if you enter enough data.

You probably don't need to worry about that just yet; just keep it in mind for the future. For now, you can allocate "enough" space (say, 100 bytes) and be careful not to enter too much data. That should be enough to get your program working. (Check the documentation for scanf , and think about using something like "100s" .)

And keep in mind that scanf("%s", ...") reads a whitespace-delimited input string; if you type "John Doe", it will only read the "John", leaving " Doe" for the next input operation.

(I hope this isn't too overwhelming.)

You are passing uninitialized pointers to scanf , which uses them to perform the writes; this is undefined behavior. You are also passing an address of a string pointer to scanf and printf ; strings in C are pointers already, you should not pass pointers to them to I/O routines.

If you know a limit on the number of characters in a name / a city name, you can read strings like this:

char buf[128]; // 127 is the limit; buffer needs an extra character
printf("please enter name:\n");
scanf("%127s", buf);
size_t len = strlen(buf)+1; // plus one for null terminator
tmp->name = malloc(len);
strcpy(tmp->name, buf);
printf("%s\n", tmp->name); // No ampersand

You've allocated the space for the structure containing three pointers. You need to allocate the space for the two strings, too. You should also ensure that the next field is appropriately initialized — probably with NULL.

Personally, I would not bother with the DATAS typedef, and it is probably best to keep all upper-case names for macros (the FILE * type notwithstanding).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM