#include <stdio.h>
#include <stdlib.h>
char *ptr;
int n;
int main()
{
ptr = (char *)calloc(n, sizeof(char));
// First ID
printf("Enter the length of your employ ID\n");
scanf("%d", &n);
for (int i = 0; i <= n; i )
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i )
{
printf("%c", ptr[i]);
}
// Second ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i = 0; i <= n; i )
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i )
{
printf("%c", ptr[i]);
}
// Third ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i =0; i <=n; i )
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i )
{
printf("%c", ptr[i]);
}
return 0;
}
I tried to Get Ids of three people but the program doesnt work and after taking the input once it just exits : ( . It works fine when I use realloc once but not twice can someone explain why ? it takes the input and then exits
CodePudding user response:
The statement:
int n;
declares n
at file scope. Objects declared at file scope have static storage duration and are always initialised. In the absence of an explicit initialization, they are implicitly initialised to zero.
From the C standard C11 6.7.9/10:
"... If an object that has static or thread storage duration is not initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;"
Accessing out of bounds memory:
Then:
ptr = (char *)calloc(n, sizeof(char));
allocates memory for 0 objects.
The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
On error, these functions return NULL. NULL may also be returned by a successful call to malloc() with a size of zero, or by a successful call to calloc() with nmemb or size equal to zero.
But you didn't check the return value of calloc
.
Then, this statement:
scanf("%c", &ptr[i]);
tries to access memory that wasn't allocated, and thus invokes undefined Behaviour.
Off by one error:
You have allocated space for n
elements, but the condition:
i <= n
tries to access n 1
elements, which is memory out of bounds, memory you haven't allocated, memory that doesn't belong to you, and is thus undefined behaviour. (But that's irrelevant since you didn't allocate anything in the first place).
Regarding realloc
:
The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any kind of variable and may be different from ptr, or NULL if the request fails. If size was equal to 0, either NULL or a pointer suitable to be passed to free() is returned. If realloc() fails the original block is left untouched; it is not freed or moved.
Which means that if it fails and returns NULL
, then ptr
gets initialised with NULL
and you lose all access to the original memory.
One solution is to use another pointer:
char *new = realloc(ptr, size);
if (!new) { /* if realloc failed */
/* deal with it however you wish */
}
/* If we got here, it means that we weren't bounded */
ptr = new;. /* Now ptr points to the new memory, if it didn't already */
new = 0; /* This avoids a dangling pointer */
/* some code relevant to ptr here */
free(ptr); /* For every allocation, there must be a call to free */
Side note: You shouldn't cast the result of malloc
and family. It's redundant and may hide a bug. The void *
returned by these functions is automatically promoted to the correct type.
Trailing newline:
scanf("%d", &n);
leaves a newline in the input buffer, which automatically gets read by subsequent calls to scanf, and you might never be prompted for input.
Instead of:
scanf("%c");
Use " %c"
with a leading blank to skip optional white space:
scanf(" %c");
CodePudding user response:
First of all, please note that you're using:
ptr = (char *)calloc(n, sizeof(char));
when n
isn't explicitly initialized in file scope so it is automatically initialized to 0. So basically you overwrite a buffer of size 0 in:
for (int i = 0; i <= n; i )
{
scanf("%c", &ptr[i]);
}
while exceeding the size allocated with i <= n
which sould be i < n
, that is probably why.
Second, you must free your memory allocation at the end using free
and check allocation's success.
Third, when using strings, you might want to use scanf
using %s
, unless you have a specific reason.
A more clear and less error prone implementation may be:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size, times, i;
char *ptr;
printf("Enter the number of IDs to enter\n");
scanf("%d", ×);
for (i = 0; i < times; i) {
printf("Enter the size of new ID\n");
scanf("%d", &size);
if (size < 0) {
printf("Entered value is negative\n");
return size; // or any other error
}
// note the ' 1' so we have a NULL terminating string
ptr = (char *)calloc(size 1, sizeof(char));
if (ptr == NULL) {
printf("Error allocating ptr\n");
return -1; // or any other error
}
printf("Enter your ID\n");
scanf("%s", ptr);
printf("Your ID is: %s\n", ptr);
free(ptr);
}
return 0;
}
Hopefully I answered everything and didn't miss a thing (: