reading string of unknown size - c

i wrote this function, which read strings char by char and increase the allocated size.
for some reason im getting randomly the error " _CrtIsValidHeapPointer" in VS2010, while reading strings with around 100+ chars.
i tried to debug it, but i really cant figure whats wrong
char *unknown_size_string(){
int i=0, size=10;
char *name=NULL, *alloc_check=NULL, letter;
//allocates initial size of 10 bytes
name=(char *)malloc(sizeof(char)*size);
if(!name){return NULL;}
//reads char by char until newline reached
while((letter=getchar())!='\n'){
*((name)+i++)=letter;
//when the remaining buffer size is 1 byte, allocating another 10 bytes
if((i+1)==size){
alloc_check=name;
realloc(alloc_check,(size+=10)*sizeof(char));
if(!alloc_check){return name;}
name=alloc_check;
}
}
*((name)+i)='\0';
return name;
}
any help would be appreciated.
thanks

Aside from the comments about taking into account null-termination byte, the main problem here is:
realloc returns the new allocated area (which may be the same, may be not).
So you have to assign back alloc_check in realloc(alloc_check,(size+=10)*sizeof(char)); or you just create a memory leak and keep writing in an old location.
alloc_check = realloc(alloc_check,(size+=10));
(well, when the size is greater, the location isn't guaranteed to change everytime, but it has to sometimes when there's not enough contiguous space)
Aside: name=(char *)malloc(sizeof(char)*size); => name=malloc(size); (size of char is always 1, and no need to cast malloc pointer)
Extract from N5170:
When sizeof is applied to an operand that has type char,unsigned char,or signed char, (or a qualified version thereof) the result is 1.

Related

Why char pointer saving data more than allocated memory in C?

While working on dynamic memory allocation in C, I am getting confused when allocating size of memory to a char pointer. While I am only giving 1 byte as limit, the char pointer successfully takes input as long as possible, given that each letter corresponds to 1 byte.
Also I have tried to find sizes of pointer before and after input. How can I understand what is happening here? The output is confusing me.
Look at this code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int limit;
printf("Please enter the limit of your string - ");
gets(&limit);
char *text = (char*) malloc(limit*4);
printf("\n\nThe size of text before input is %d bytes",sizeof(text));
printf("\n\nPlease input your string - ");
scanf("%[^\n]s",text);
printf("\n\nYour string is %s",text);
printf("\n\nThe size of char pointer text after input is %d bytes",sizeof(text));
printf("\n\nThe size of text value after input is %d bytes",sizeof(*text));
printf("\n\nThe size of ++text value after input is %d bytes",sizeof(++text));
free(text);
return 0;
}
Check this output:
It works because malloc usually doesn't allocate the same number of bytes you pass to it.
It reserves memory multiple of "blocks". It usually reserve more memory to "cache" it for next malloc calls as an optimization. (it is an implementation specific)
check glibc malloc internals for example.
Using more memory than allocated by malloc is an undefined behavior. you may overwrite metadata of malloc saved on heap or corrupt other data.
Also I have tried to find sizes of pointer before and after input. How
can I understand what is happening here? The output is confusing me.
The size of pointer is fixed for all pointer types in a machine, it is usually 4/8 bytes depending on the address size. It doesn't have anything to do with data size.
Welcome to the world of Undefined Behaviour!
char *text = malloc(limit*4); (don't cast malloc in C) will make text point the the first element of an array of size limit*4.
C will not prevent you to write past the end of any array, simply the behaviour is undefined by the standard. It may work fine, or it may crash immediately, or you may experience abnormal behaviour later in the program.
Here, the underlying system call has probably allocated a full memory page (often 4k), and as you have not used another malloc you have just used a memory belonging to the process but still officially unused. But do not rely on that and never use it in production code.
And sizeof does not make sense with pointers. sizeof(text) is sizeof(char *) (same for sizeof(++text) for same reason) and is the size of a pointer (generaly 2, 4 or 8 bytes) and sizeof(*text) is sizeof(char) which by definition is 1.
C is confident that you as the programmer know how much memory you have asked, and will not try to use more. Anything can happen if you do (including expected result) but do not blame the language or the compiler if it breaks: only you will be guilty.

inserting a substring into another string in c

i just started learning c. i am doing an exercise and the question is as follows.
Write a function called insertString to insert one character string into another string.The arguments to the function should consist of the source string, the string to be inserted, and the position in the source string where the string is to be inserted. So, the call insertString (text, "per", 10); with text as originally defined "the wrong son" results in the character string "per" being inserted inside text, beginning at text[10].Therefore, the character string "the wrong person" is stored inside the text array after the function returned.
#include<stdio.h>
int insertString(char[],char[],int);
int stringLength(char[]);
int main()
{
char text[]="the wrong son";
int result=insertString(text,"per",10);
if(result!=-1)
printf("string 1 is : %s \n",text);
else
printf("Not possible\n");
return 0;
}
int insertString(char a[],char b[],int pos)
{
int i=0,j=0;
int lengthA=stringLength(a);
int lengthB=stringLength(b);
if(pos>lengthA)
return -1;
for(i=lengthA;i>=pos;i--)
a[i+lengthB]=a[i];
for ( i = 0; i < lengthB; ++i )
a[i + pos] = b[i];
return 1;
}
int stringLength(char x[])
{
int length=0;
while(x[length]!='\0')
length++;
return length;
}
i have done this and it's working too. but i am receiving a message abort trap : 6. when i looked upon it, i learned it's an error because i am writing to the memory that i don't own. since i have used variable length character arrays, wherever the null character is, indicates the end of array and i am trying to extending it by inserting a string, that's my understanding. am i right so far?
i am also moving the null character. i don't know whether it's right or wrong.
so is there a way to get around this error? Also, i don't know pointers yet and they're in the next chapter of the textbook .
Any help in this would be appreciated very much.
A variable-length array is a very specific C construct that has nothing to do with what your textbook calls "variable length arrays". If I were you I would not trust this textbook if it said that 1+1=2. So much for it.
A character array that ends with a null character is called string by pretty much everyone, everywhere.
char text[]="the wrong son";
Your textbook led you to believe that text will hold as many characters as you need. Alas, there is no such thing in C. In fact text will hold exactly as many characters as there are in its initializer, plus 1 for the null terminator, so you cannot insert anything in it.
In order for your program to work, you need to explicitly allocate as many characters for text as the resulting string will contain.
So as there are 14 characters in "the wrong son" (including the terminator) and three characters in "per" (not including the terminator), you need 17 characters in total:
char text[17]="the wrong son";
You can also check your calculations:
int result=insertString(text, "per", 10, sizeof(text));
...
int insertString(char a[], char b[], int pos, int capacity)
{
...
if (lengthA + lengthB + 1 < capacity)
return -1;
...
First you must understand what the difference between C-programming and other programming languages are manual memory management and pointers.
In C you have to do everything yourself but you have total control of everything, in other languages like Java a lot is made automatically for you but you can't open the hood.
Memory handling in C is the essence of C and is very different from for instance Java that looks very alike C. Java and C syntax are very much alike, but in two completely different worlds.
C++ is an extension of C that allow similar features like in Java, but still memory wise is C.
There are two types of memory in C:
Automatic string array (declared as char xx[]) with the exact length of its initialization number or defined string length (the number between the []) + 1 (for null termination), can't be changed.
Dynamic memory (declared as char*) is allocated with calloc() or alloc() and can be changed in length with realloc() and must be manually freed or else the program will leak memory (still allocate memory after the program is ended (some OS has automatic clean-up of that but it is bad style C programming not freeing memory)).
Dynamic memory is delivered to a pointer (char*) that points to the memory allocated. Pointers can point at any type of memory also string arrays and even integers.
A pointer is an integer, a number pointing at the available memory address in the OS, the OS keep track of the memory of each pointer, but do not clean it up like in Java.
Also note that after the realloc the old memory of the old pointer is freed by the command, new is allocated that you must manually free, later after use.
It is possible to send a pointer (it is just a number) into a function and the function changes the pointer (it is just another number pointing at memory (that might not be the same)).
Because of this it is essential to return the new pointer from functions that might have changed its content.
In practice the core of C-programming is pointer programming and the programmer must have a firm track of the memory or the program goes berserk, you have to learn the routines.
With pointer programming it is possible to have absolute control over all the memory and the functions becomes normally very efficient, fast and memory lean.
This is used also when we are talking about huge data like in high resolution pictures or video content, and often the only way to get performance.
Extended level - pointer to pointers
When getting more advanced it is possible to send the pointer of a pointer (char**) to a function allowing the function to amend the content of a pointer like reallocation of a string and the updated pointer will be readable by the calling function. This way multiple pointers can be amended (there is only one return value).
A pointer to a pointer, points to the memory where the pointer address (the number that points to the memory) is stored, so sending it into the function the function can change the pointers number (what memory it points at) and the calling function can read it (the same pointer have a new value).
Pointers to pointers are normally used for instance in database programming with linked lists being able to control a huge number of memory chunks in a long chain, and being able to handle them smoothly.
Most other programming languages basic system is programmed in C, so normally it is possible to integrate chunks of C--code to improve performance.
ANSI C is the same in all computers so it is also a way of making code real portable from system to system and work the same in them all.
Lets check out your case, here is a sample code to show.
#include<stdlib.h>
#include<string.h>
#include <stdio.h>
char* insertString(
char* pTarget,
char* pInput);
void main(void)
{
char Target[9] = { "Hello" };
char Target2[9] = { "Hi" };
char Input[] = { " World" };
Target and Target2 are automatic string arrays with the exact length of its initialization number, the number between the[] and Input is defined by the string length(+1 for null termination), can't be changed.
So, the length of Input is defined as 7 bytes, six letters +1, as Target and Target2 are defined as 9 bytes (can contain 8 letters), can't be changed, they are string arrays.
This below will not work, because Target is too short, only 9 chars space (enough for 8 letters) and Target + Input is 11 letters, the program will crash.
strcat(Target, Input);
But this will work because Target2 is 9 chars (space for 8 letters) and Target2 + Input is 8 letters, so it fits.
strcat(Target2, Input);
printf("%s\n", Target2);
This below will not work because Target is an automatic char array with the exact length of its initialization number or string length +1 (for null termination), its length can't be changed.
They are fixed in length and not possible to extend or shrink in length, can't realloc them, and they will be freed automatically at the end of the function.
In fact, it is created normally in another set of memory than the dynamic memory and is protected from change.
pTarget = insertString(Target, Input);
{
This below will work because it is dynamically allocated memory(by a calloc or alloc command) that can be reallocated to any size.
Dynamic memory(volatile) in C is not automatic like in other programming languages, must be taken care of manually.
Usually in C a p is put ahead for pointers to differentiate them from automatic string arrays.
Dynamically allocated memory must be manually freed after use or the program will leak memory, it is not Java with auto clean - up.
char* pTarget = calloc(strlen(Target) + 1, sizeof(char));
if (pTarget) {
strcpy(pTarget, Target);
pTarget = insertString(pTarget, Input);
Also notice you as a programmer must check that you got the memory you asked for by the memory allocation command calloc.
If not (very unlikely memory is unavailable in 2022) you can't perform the action and, you fail, or the program will crash.
printf("%s\n", pTarget);
free(pTarget);
}
else
printf("%s\n", "Failure!");
}
}
char* insertString(
char* pTarget,
char* pInput)
{
We are here reallocating the memory to get it enlarged to fit our use
pTarget = realloc(pTarget, (strlen(pTarget) + strlen(pInput) + 1) * sizeof(char));
The old memory is freed by realloc and a new larger is allocated for us.
Now the pointer (the number that points to memory) might not be the same as before realloc.
A pointer is a storage of the number and the same storage pTarget contains the new number to the new data, OK.
if (pTarget)
strcat(pTarget, pInput);
return pTarget;
}
int replace_substring (char *str, char *substr, char *new_substr) {
int pos = delete_substring (str, substr); /* first delete the existing substring */
if (pos == -1) return pos; /* substring not found, return */
insert_substring (str, pos, new_substr); /* add the new substring at the deleted position */
}
int replace_substring (char *str, char *substr, char *new_substr) {
int pos = delete_substring (str, substr); /first delete the existing substring/
if (pos == -1) return pos; /substring not found, return/
insert_substring (str, pos, new_substr); /add the new substring at the deleted position/
}

Copying part of char array into new char array fails

I want to copy a part of char array into a new one
void match(char* probe, char* pattern)
char* matchText;
//the char-array probe in this example is at least 12 characters long
//I'm only writing numbers in the strncopy-command to make it easier to understand
strncpy (matchText, probe + 5, 5 );
Upon running that the debugger quits with an error.
What am I doing wrong?
You need to allocate memory to matchText, what you have is just an pointer.
It must have enough memory allocated using malloc(since it is a pointer) to hold the string being copied in to it, or what you get is Undefined Behavior.

malloc(sizeof(s)) allocates less memory than expected?

hey i am having problems using the sizeof operator in malloc. For example see the foll. code-
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char * copy(char *s)
{
char *t=malloc(sizeof(s));
char *ptr=s;
int i=0;
do
{
t[i++]=*ptr++;
}
while(*ptr!='\0');
return t;
}
int main()
{
char *s="hello adsjahsjkdhjkashdkjaskdasldjlasjdlajsdlkjaslkdjalsjdlasjdljasdljasdkljklsdjlasdsadasdasd";
char *b=copy(s);
printf("%s\n",b);
free(b);
return 0;
}
on ideone, it gives the error:-
* glibc detected ./prog: free(): invalid next size (fast): 0x09bcf008 **
But when i replace malloc(sizeof(s)) with malloc(strlen(s)+1) , the program works perfectly. So whats the problem?
NOTE:this is just a small prog i created to demonstrate the problem i was having in another code.
The operator sizeof doesn't do what you want on pointers. It yields the size of the pointer on your machine (which will be something like 4 or 8).
You can think of it this way: the array decays to a pointer when passed to a function and the information regarding its size is "lost".
Also note your loop doesn't fill in the 0 terminator.
You should use strlen instead of sizeof in the copy function:
char * copy(char *s)
{
char *t=malloc(strlen(s) + 1);
char *ptr=s;
int i=0;
do
{
t[i++]=*ptr++;
}
while(*ptr!='\0');
return t;
}
The problem is that sizeof does not return the value you need, that function will return the size of the char *s (probably 4 or 8 -> bytes used to storage that pointer). Check the documentation links to understand more clearly.
One more thing, if you are doing that in order to practice your C skills is OK but if you are not, you will probable just want to use the strcpy function.
Hope it helps.
sizeof(s) returns the size of char *s which is 4 (on 32 bit) or 8 (on 64 bit) systems.
arrays and strings with size information gets degenerated to pointers losing its size attributes when it is passed as a parameter to a function
So when you are calculating the size of the parameter s it either returns 32/64 based on your bitness.
instead of sizeof, you should actually do strlen and add one to it to accommodate the null character.
instead of
char *t=malloc(sizeof(s));
try
char *t=malloc(strlen(s)+1);
Please note:
There are other design issues with your code
When passing a pointer argument which is not supposed to change, you should declare it const.
Generally returning an address of a locally generated heap storage is not a good practice and is the major cause of memory leak, if cal-lee ever forgets to free the storage. Instead pass it as a non-const parameter to the function.
sizeof returns the size of the pointer (usually 4 or 8 bytes), not the size of the pointed-to object. (There is no way to get at the latter information. sizeof is effectively a compile-time constant, by the way.)
s is a pointer to char, so malloc(sizeof(s)) allocates space for one pointer to char -- typically 2-8 bytes, most often 4 bytes. As it stands, it'll always allocate this fixed amount of space, regardless of the length of string you passed in. In your test, you're passing a much longer string than that, so you overflow the buffer you allocated.
You're already given the correct answer: under the circumstances, strlen is the right function to find the size.
malloc is declared in , so we #include that header in any program that calls malloc. A ``byte'' in C is, by definition, an amount of storage suitable for storing one character, so the above invocation of malloc gives us exactly as many chars as we ask for. We could illustrate the resulting pointer like this:

C: using sprintf and strncpy inserting data into an array of pointers

I have a structure that has an array of pointers. I would like to insert into the array digits in string format, i.e. "1", "2", etc..
However, is there any difference in using either sprintf or strncpy?
Any big mistakes with my code? I know I have to call free, I will do that in another part of my code.
Many thanks for any advice!
struct port_t
{
char *collect_digits[100];
}ports[20];
/** store all the string digits in the array for the port number specified */
static void g_store_digit(char *digit, unsigned int port)
{
static int marker = 0;
/* allocate memory */
ports[port].collect_digits[marker] = (char*) malloc(sizeof(digit)); /* sizeof includes 0 terminator */
// sprintf(ports[port].collect_digits[marker++], "%s", digit);
strncpy(ports[port].collect_digits[marker++], digit, sizeof(ports[port].collect_digits[marker]));
}
Yes, your code has a few issues.
In C, don't cast the return value of malloc(). It's not needed, and can hide errors.
You're allocating space based on the size of a pointer, not the size of what you want to store.
The same for the copying.
It is unclear what the static marker does, and if the logic around it really is correct. Is port the slot that is going to be changed, or is it controlled by a static variable?
Do you want to store only single digits per slot in the array, or multiple-digit numbers?
Here's how that function could look, given the declaration:
/* Initialize the given port position to hold the given number, as a decimal string. */
static void g_store_digit(struct port_t *ports, unsigned int port, unsigned int number)
{
char tmp[32];
snprintf(tmp, sizeof tmp, "%u", number);
ports[port].collect_digits = strdup(tmp);
}
strncpy(ports[port].collect_digits[marker++], digit, sizeof(ports[port].collect_digits[marker]));
This is incorrect.
You have allocated onto collect_digits a certain amount of memory.
You copy char *digits into that memory.
The length you should copy is strlen(digits). What you're actually copying is sizeof(ports[port].collect_digits[marker]), which will give you the length of a single char *.
You cannot use sizeof() to find the length of allocated memory. Furthermore, unless you know a priori that digits is the same length as the memory you've allocated, even if sizeof() did tell you the length of allocated memory, you would be copying the wrong number of bytes (too many; you only need to copy the length of digits).
Also, even if the two lengths are always the same, obtaining the length is this way is not expressive; it misleads the reader.
Note also that strncpy() will pad with trailing NULLs if the specified copy length is greater than the length of the source string. As such, if digits is the length of the memory allocated, you will have a non-terminated string.
The sprintf() line is functionally correct, but for what you're doing, strcpy() (as opposed to strncpy()) is, from what I can see and know of the code, the correct choice.
I have to say, I don't know what you're trying to do, but the code feels very awkward.
The first thing: why have an array of pointers? Do you expect multiple strings for a port object? You probably only need a plain array or a pointer (since you are malloc-ing later on).
struct port_t
{
char *collect_digits;
}ports[20];
You need to pass the address of the string, otherwise, the malloc acts on a local copy and you never get back what you paid for.
static void g_store_digit(char **digit, unsigned int port);
Finally, the sizeof applies in a pointer context and doesn't give you the correct size.
Instead of using malloc() and strncpy(), just use strdup() - it allocates the buffer bin enough to hold the content and copies the content to the new string, all in one shot.
So you don't need g_store_digit() at all - just use strdup(), and maintain marker on the caller's level.
Another problem with the original code: The statement
strncpy(ports[port].collect_digits[marker++], digit, sizeof(ports[port].collect_digits[marker]));
references marker and marker++ in the same expression. The order of evaluation for the ++ is undefined in this case -- the second reference to marker may be evaluated either before or after the increment is performed.

Resources