Copying part of char array into new char array fails - c

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.

Related

Why does malloc seemingly allow me to write over memory? [duplicate]

This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 4 years ago.
Why does this not return a segmentation fault 11?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char *test;
test = (char*) (malloc(sizeof(char)*3));
test = "foo";
printf("%s\n", test);
test = "foobar";
printf("%s\n", test);
return 0;
}
My outcome is
foo
foobar
I'm fairly new to C, but when I was compiling this using both gcc on mac and Windows Debugger on Windows 10, it doesn't crash like I expected.
My understanding is that by using (char*) (malloc(sizeof(char)*3)), I am creating a character array of length 3. Then, when I assign test to the string foobar I am writing to 6 array positions.
I'm left sitting here, staring at my apparently valid, runnable code scratching my head.
test = "foo";
Here you do not copy the string to the allocated memory, test no longer points to the allocated memory, instead it points to the string literal "foo". Same goes for "foobar". Also as pointed out in the comments the address of the allocated memory is lost and therefore it is a memory leak (since there is no way to retrieve the address of the memory).
If you want to copy a string to another destination you need to use strcpy or loop over every character.
If you write or read outside bounds of the allocated space you are invoking undefined behavior. That means that basicly everything can happen, also that it works.
Your program never writes to the location pointed to by the return from malloc(). All you've done with e.g. test = "foo"; is change what test points to, which by the way is a memory leak since you've then lost what malloc() returned.
To properly use the memory you allocated with malloc(), use strcpy(), snprintf(), etc.
Also, don't forget the null terminator in your C strings. To properly store e.g. "foobar" you need at least 7 bytes, not 6.
First thing is that you waste the memory allocated by malloc unnecessorily by storing the address of foo into that.
If you are going to point to string in code section then there is no need to allocate memory to the pointer.
When to allocate memory to pointer
e.g. when you intended to scan 'n' number of bytes from keyboard in pointer.
char *ptr,num_char;
scanf("%d",&num_char);
ptr = (char *)malloc(num_char*sizeof(char));
scanf("%s",ptr);

reading string of unknown size

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.

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/
}

Segmentation fault when using strcpy?

I'm trying to define a path at compile time by passing:
-DDCROOTDEF='"/path/to/stuff"'
on the compile line. I then try to get use this in the code like:
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
char *pftf=ptr_path;
gdImageStringFT(pimg,brect,iclr,pftf,pts,ang,ixp,iyp, (char *)cbuf);
Which gives me a segmentation fault. However, if I try to print the string first:
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
char *pftf=ptr_path;
printf("%s\n",pftf);
gdImageStringFT(pimg,brect,iclr,pftf,pts,ang,ixp,iyp, (char *)cbuf);
It works just fine. What intricacy of char pointer's am I missing here?
Thanks
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
You never initialize ptr_path.
It doesn't work in the second code snippet, you are just getting unlucky and it appears to work. You're still using an uninitialized pointer and trying to write to who knows where in memory.
You need to initialize ptr_path to point to an array of char that is at least strlen(DCROOTDEF) + 1 in length. You also need to check the length of DCROOTDEF before copying its contents into the array to be sure that it is not too long. You can do so manually using strlen or you can use a length-checked copy function like strlcpy.
The pointer ptr_path is not initialized to point at writable memory, which is why dereferencing it using strcpy() is crashing.
You need to call e.g. malloc() to get the space, first:
char * ptr_path = malloc(PATH_MAX);
Or something like that.
In
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
the pointer is not bound to a legally allocated block of memory, so your program runs into undefined behavior. You need to allocate a buffer first - for example by using malloc(). Be sure that the buffer is large enough to hold the resulting string together with the terminating null character.

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