Array with uninitialized size inside struct - c

In the program
#include<stdio.h>
struct t {
char a[5];
char b[];
} temp;
int main(){
temp.b[0] = 'c';
temp.b[1] = 'b';
temp.b[2] = '\0';
printf("Size of struct = %lu\n", sizeof(temp));
printf("String is %s\n", temp.b);
printf("Address of temp = %p\n", &temp);
printf("Address of array a = %p\n", &(temp.a));
printf("Address of b = %p\n", &(temp.b));
}
with output
Size of struct = 5
String is cb
Address of temp = 0x601035
Address of array a = 0x601035
Address of b = 0x60103a
In this program, how exactly is array b being allocated? How long is it? Is this some undefined behavior, which is only succeeding in the dummy program as I am not doing anything else. Running into gdb, I can access some memory locations initialized as zero, which makes me suspect that it is allocating some memory.
I do have an api that requires me to format one element of struct as int a[][SIZE], and I am confused about that.
Also, why is sizeof not taking into account at least something from array b. I am not sure if it is taking it as an array or pointer.

The way you use it is undefined behavior. To answer your immediate question, with static or automatic storage (as you use it), this member has a size of 0. So any index will be invalid. It "seems" to work in your experiment, but remember, c doesn't do any bounds checking. In fact, you're doing invalid writes and you're just lucky your example doesn't crash and burn.
Such a member is only allowed as last member of a structure and the reason for this is you can use it with dynamic storage:
struct t *temp = malloc(sizeof(struct t) + 5 * sizeof(char));
will allocate an instance of struct t with temp->b being an array of char of size 5.

Related

Can someone explain why I'm getting segmentation fault 11?

Here is my code:
int main() {
typedef struct {
int recordCount;
char *firstName;
char *secondName;
char *id;
char *email;
}student;
student *students = malloc(sizeof(*students));
int i = 0;
while (students[i].firstName[0] != '.'){
students[i].firstName = (char *)malloc(sizeof(char*));
scanf("%s", students[i].firstName);
i++;
students = realloc(students, sizeof(students) * (i + 1));
}
}
When I run it through a for loop it works, I'm pretty sure it's just something silly going on with my while loop.
malloc returns a block of uninitialized memory. So students[i].firstName is an uninitialized pointer which you attempt to dereference. Reading and dereferencing an uninitialized pointer invokes undefined behavior, which in this case manifests as a crash.
When you do allocate space for the firstName member, you only allocate sizeof(char*) bytes for it which is the size of a pointer, not necessarily the length of a string you would want to read.
Create a buffer to read strings into that's big enough for what you might need, then use strdup to create a copy to assign to the relevant pointer.
student *students = NULL;
int i = 0;
char str[100];
scanf("%99s", str);
while (str[0] != '.'){
students = realloc(students, sizeof(*students) * (i+1));
students[i].firstName = strdup(str);
i++;
scanf("%99s", str);
}
For a start,
students[i].firstName = (char *)malloc(sizeof(char*));
allocates enough space for a character pointer, typically four or eight bytes.
While there are some names that will fit in that (such as Pax or Bob), the vast majority probably won't.
You need to allocate enough space for the largest name (and string terminator), such as with:
#define MAX_NAME_LEN 100
students[i].firstName = malloc(MAX_NAME_LEN + 1);
There are plenty of issues in your code.
When you are using malloc, you actually specify the data type and not the pointer type which is I believe is not your intent here. If you are specifying a pointer type with sizeof, the pointer will point to a memory location having the size of the pointer. This is not what you want in this case.
After the line student *students = malloc ... . The students will point to a memory location which will hold zero values in firstName. You need to use malloc for these. Since you are not doing this you are getting a segmentation fault because you are dereferencing an invalid pointer (pointing to location 0). You are trying to access it first and using malloc afterwards.
If you
student *students = malloc(sizeof(*students));
you are allocating size of one pointer. What you want to do is instead
student *students = malloc(sizeof(students));
and for the same reason, students[i].firstName = (char *)malloc(sizeof(char*)) quite surely do not have enough memory for your name as well, try malloc(sizeof(char)*100) or so.

assign and allocate memory for a pointer inside a struct in C?

Suppose I have a struct:
struct b {
unsigned short num;
unsigned short size;
unsigned char *a;
};
I then declare a pointer that points to a struct of b:
struct b *foo=malloc(sizeof(struct b));
how do I allocate memory for foo's a and assign a to point to a character string?
It's not that different, e.g, to allocate the memory for the string hello:
char *hello = "hello";
foo->a = malloc(strlen(hello) + 1);
strcpy(foo->a, hello);
Actually, struct b *foo = malloc(sizeof *foo); already allocates enough space to accomodate a char pointer, so it depends on what you want to do with foo->a (ps: because foo is a pointer, you need to use the indirection operator).
If foo->a (or, *(foo).a) can be a constant string, you can simply do this:
struct b *foo = malloc(sizeof *foo);
foo->a = "A constant string";
Note that, because this is (sort of) equivalent to:
const char *const_str = "this is read-only";
You can't change anything about the chars a points to. The member a is assigned an address of a string constant in read-only memory. In short:
foo->a = "constant";
printf("%c%c%c\n", foo->a[0], foo->a[2], foo->a[4]);//prints cnt
foo->a[0] = 'C';//WRONG!
If you want to be able to change the string, use this:
foo->a = malloc(50 * sizeof *(foo->a)));
The sizeof is optional here, since the size of char is guaranteed to be size 1, always.
To assign/copy a string you use strcat, strcpy, memcpy, strncat, sprintf and the like
strcpy(foo->a, "constant");
printf("%c%c%c\n", foo->a[0], foo->a[2], foo->a[4]);//still prints cnt
foo->a[0] = 'r';
printf("%c%c%c\n", foo->a[0], foo->a[2], foo->a[4]);//still prints rnt
Now you can change the string a points to, but as a result, you'll have to free this memory, too, when you're done with it:
//wrong:
free(foo);//works, but won't free the memory allocated for foo->a
//better:
free(foo->a);
free(foo);
'foo->a' (operator ->)should be used
First you have to assign memory for foo by malloc, then it will contain the address of the inside pointer called "a". When you have the memory address of "a" (not the "pointed to" but the address where the pointed to address is stored), you can store addresses there.
so:
1. struct b *foo = malloc(...)
2. foo->a = malloc(...)

String copy(strcpy)

I have the following code.
#include <string.h>
#include <stdio.h>
int main()
{
char * l;
*l = 'c';
*(l+1) = 'g';
*(l+2) = '\0';
char *second;
strcpy(second, l);
printf("string: %s\n", second);
}
When I run it is says:
The output says "Segmentation fault"....any suggestions??
Thanks
l is an uninitialized pointer; you can't dereference it. You should allocate enough space to write its contents (statically (1) or dynamically (2)).
char l[3]; /* (1) */
#include <stdlib.h>
char *l = malloc(3); /* (2) */
It is the same error with strcpy: second is an unitialized pointer, you can't write into it.
You will learn to despise the Segmentation Fault error...
It's usually called when you try to access memory that is not yours. Most common occurrence would be when you try to access an array index that is out of bounds.
char *l just creates a pointer to a char. What you want is a string, which in C is defined as an array of chars. So when you try to access the next location in memory of whatever l is pointing to (which will probably just be garbage), you're going to access memory that isn't yours, thus Segmentation Fault
You could get memory with malloc or point the pointer to an already existing variable.
char word[3];
char *l;
l = word;
Now you can do such assignments:
*l = 'c';
*(l+1) = 'g';
*(l+2) = '\0';
but now that you want to copy it to another pointer, this pointer must be pointing to another string or you should allocate memory for it.
char *pointer_to_second;
char second[3];
pointer_to_second = second;
or if you prefer to get dynamic memory, change the 3 lines above be this one bellow:
char *pointer_to_second = malloc(sizeof(char) * 3);
after that you can do what you wanted:
strcpy(pointer_to_second, l);
But remember, if you are using a C compiler you must declare all variables at the beggining, otherwise you will get an error. If you are using a C++ compiler you won't have to concern about it.
Segmentation fault happens when you try to access a field that doesn't belong to your vector. For example, if you try this:
printf("The value in position 3 of my pointer is %c\n", *(l + 3));
You will probably get an error, because you pointer have 3 positions and you are trying to acess the 4th one.

Segmentation fault while using malloc with char pointers

I am new to C and learning structs. I am trying to malloc a char pointer with size 30 but it is giving a segmentation fault(core dump). I searched it on the internet & SO but am not able to resolve this. Any help will be much appreciated.
Probably I am accessing the char* member of the struct incorrectly ?
typedef struct{
int x;
int y;
char *f;
char *l;
}str;
void create_mall();
void create_mall() //Malloc the struct
{
str *p;
p->f = (char*)malloc(sizeof(char)*30); // segmentation fault here
p->l = (char*)malloc(sizeof(char)*30);
printf("Enter the user ID:");
scanf("%d",&p->x);
printf("\nEnter the phone number:");
scanf("%d",&p->y);
printf("\nEnter the First name:");
scanf("%29s",p->f);
printf("\nEnter the Last name:");
scanf("%29s",p->l);
printf("\nEntered values are: %d %d %s %s\n",p->x,p->y,p->f,p->l);
}
int main(void)
{
create_mall();
return 0;
}
Here's your problem:
str *p;
You've declared a pointer to an instance of str, but you haven't initialized it with a value. You either need to move this variable to the stack:
str p;
...or malloc some memory for it first:
str *p = (str*)malloc(sizeof(str));
You never allocated space for the struct itself, only a pointer to it.
Try something like:
str *p = malloc(sizeof(str));
As many people have pointed out, you need to allocate memory for that str struct, before writing the fields of it.
The best way to do so in C is:
p = malloc(sizeof *p);
This has the following advantages:
No cast, since no cast is needed in C and having a cast can hide actual errors.
No duplication of type information, by using the sizeof operator to compute how much storage is needed for the value p points at.
When you then allocate the string space, you can simplify it to:
p->f = malloc(30);
Because:
No cast, for the very same reason.
C guarantees that sizeof (char) is always 1, so using it like you did adds nothing, 1 * 30 is always just 30.
Last, you should always check the return value of malloc() before using it, since it can fail and return NULL.
Check for NULL values in return of malloc() function.
Also str *p; < is not initialised.
initialize p as str *p = malloc(sizeof(str));
The problem lies here.
str *p; ---> Problem Line 1<br>
p->f = (char*)malloc(sizeof(char)*30); ----> Problem Line2
p->l = (char*)malloc(sizeof(char)*30);
You have declared a pointer p of type str.
Problem 1:
You have not initialized this pointer to NULL. Thus, p can point to anything.
Problem 2:
Since p is an uninitialized pointer, p->f can point anywhere which is causing the segfault.
Below is the correct way
str *p = NULL;
p = malloc(sizeof(str));
// Check p for NULL
memset(p, 0, sizeof(str));
Now you have an initialized memory pointed by p. You are now free to use it as you want.

Dereferencing a double pointer and using index operator

I am passing a double pointer of type char ** to a function. Inside that function, I need to dereference the pointer and then index through the character array.
Unfortunately, I am getting a core dump when I try to assign a capital letter back into the array.
I need help on how to do this. (This is not homework, just a personal project.)
void buffer(char **ppline);
int main()
{
char *line="The redcoats are coming!";
buffer(&line);
printf("\nline = %s\n",line);
return(0);
}
void buffer (char **ppline)
{
int i=0;
char a;
for (i=0; i < strlen(*ppline); i++)
{
a = toupper( (*ppline)[i] ); /* THIS LINE CAUSES THE CORE DUMP */
((*ppline)[i]) = a;
}
return;
}
A string literal in "" is constant. You cannot modify it as you're doing, as that is undefined behavior. Try this, which allocates storage and copies the string literal into it:
void buffer(char **ppline);
int main()
{
char line[] = "The redcoats are coming!";
buffer(&line);
printf("\nline = %s\n",line);
return(0);
}
void buffer (char **ppline)
{
int i=0;
char a;
for (i=0; i < strlen(*ppline); i++)
{
a = toupper( (*ppline)[i] ); /* THIS LINE CAUSES THE CORE DUMP */
((*ppline)[i]) = a;
}
return;
}
Stack, heap, datasegment(and BSS) and text segement are the four segments of process memory. All the local variables defined will be in stack. Dynmically allocated memory using malloc and calloc will be in heap. All the global and static variables will be in data segment. Text segment will have the assembly code of the program and some constants.
In these 4 segements, text segment is the READ ONLY segment and in the all the other three is for READ and WRITE.
char []a="The redcoats are coming!"; - This statemnt will allocate memory for 25 bytes in stack(because local variable) and it will keep all the 24 characters plus NULL character (\0) at the end.
char *p="The redcoats are coming!"; - This statement will allocate memory for 4 bytes(if it is 32 bit machine) in stack(because this is also a local variable) and it will hold the pointer of the constant string which value is "The redcoats are coming!". This byte of constant string will be in text segment. This is a constant value. Pointer variable p just points to that string.
Now a[0] (index can be 0 to 24) means, it will access first character of that string which is in stack. So we can do write also at this position. a[0] = 'x' This operation is allowed because we have READ WRITE access in stack.
But p[0] = 'x' will leads to crash, because we have only READ access to text segement. Segmentation fault will happen if we do any write on text segment.
But you can change the value of variable p, because its local variable in stack. like below
char *p = "string";
printf("%s", p);
p = "start";
printf("%s", p);
This is allowed. Here we are changing the address stored in the pointer variable p to address of the string start(again start is also a read only data in text segement). If you want to modify values present in *p means go for dynamically allocated memory.
char *p = NULL;
p = malloc(sizeof(char)*7);
strcpy(p, "string");
Now p[0] = 'x' operation is allowed, because now we are writing in heap.

Resources