0

Given the following C code:

#include <stdio.h>
#include <string.h>

typedef struct a {
    char name[10];
} a;

typedef struct b {
    char name[10];
} b;

void copy(a *source, b *destination) {
    strcpy(destination->name, source->name);
}

This main function below runs successfully:

int main() {
    a first;
    b second;

    strcpy(first.name, "hello");
    copy(&first, &second);
    printf("%s\n", second.name);
    printf("Finished\n");
    return 1;
}

While this main function results in a segmentation fault:

int main() {
    a *first;
    b *second;

    strcpy(first->name, "hello");
    copy(first, second);
    printf("%s\n", second->name);
    printf("Finished\n");
    return 1;
}

From my understanding of C, both implementations should run identically. What are the differences between the implementations and how can I adjust the second implementation to successfully run to completion?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • You have to allocate some memory for the objects on the second implementation. – imreal Feb 27 '20 at 20:26
  • Yes, these are very different. `a first;` allocates memory on the stack for a whole structure. `a *first;` allocates memory for a pointer to a structure. You must then make that point to an actual structure you must allocate somewhere else. Until you do, it just points to some random location in memory, causing your segfault. – Lee Daniel Crocker Feb 27 '20 at 20:35

3 Answers3

3

They don't run identically because you don't allocate memory for first and second in the second example. To do that, you can allocate them using malloc:

a *first = malloc(sizeof(*first));
b *second = malloc(sizeof(*second));

If you allocate using malloc, make sure to check if the pointers are NULL before using them. If they are NULL, you should return an error or (in main) exit the program. In a non-trivial program, you should also call free on these pointers after you're done using them.

Alternatively, you can allocate them on the stack:

a first[1];
b second[1];

This does not require you to call free. I recommend this form.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • ```first``` and ```second``` are variables names, not types in your ```malloc() ``` – cocool97 Feb 27 '20 at 20:32
  • @cocool97 It works. `sizeof` can operate on objects and types, and `*first` and `*second` just happen to be objects. In fact, I would argue that this is better if the types of `first` and `second` ever change. – S.S. Anne Feb 27 '20 at 20:34
  • 1
    @cocool97 it is idiomatic to use the variable rather than the type, which here is the `sizeof` what they are pointing *to*. – Weather Vane Feb 27 '20 at 20:36
  • Yes, this is a useful idiom. You don't need the inner parens, BTW: `sizeof` is not a function, it's an operator. – Lee Daniel Crocker Feb 27 '20 at 20:39
  • @LeeDanielCrocker I understand that. I like the parentheses. – S.S. Anne Feb 27 '20 at 20:40
1

In the second code, you are only creating to pointer on a and b structs, but you aren't allocating memory for them..
You have to use the following code to properly allocate memory for your structs :

a *first = (struct a*)malloc(sizeof(struct a));
b *second = (struct b*)malloc(sizeof(struct b));
cocool97
  • 1,201
  • 1
  • 10
  • 22
  • 1. [don't cast the result of `malloc`](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) 2. you should probably get the sizes of the pointed-to object instead of the size of the type so it still works if the type is changed. Do that with `malloc(sizeof(*ptr));`. – S.S. Anne Feb 27 '20 at 20:33
  • 1
    A useful idiom is this: `a *first = malloc(sizeof *first);`. That way, you can even change the type without having the change it twice. – Lee Daniel Crocker Feb 27 '20 at 20:38
0

The program are not identical because in the second program the declared pointers

a *first;
b *second;

are not initialized, have indeterminate values and do not point tfo valid objects of the types a and b.

You have to define objects of the types a and be to which the pointers will point to.

For this purpose you could use for example the compound literal.

Here is a demonstrative program

#include <stdio.h>
#include <string.h>

typedef struct a {
    char name[10];
} a;

typedef struct b {
    char name[10];
} b;

void copy(a *source, b *destination) {
    strcpy(destination->name, source->name);
}

int main(void) 
{
    a *first = &( a ){ 0 };
    b *second = &( b ) { 0 };

    strcpy(first->name, "hello");

    copy(first, second);

    printf("%s\n", second->name);
    printf("Finished\n");

    return 0;
}

The program output is

hello
Finished
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335