C - realloc() function - proof it corrupts data - c

Look what I found with this simple code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *string;
int main(){
string = (char *) malloc(50*sizeof(char));
strcpy(string, "initi1l wording cont2ining forty-nine ch3r4cters.");
printf("BEFORE: %s\n", string);
string = (char *) realloc(string, 24*sizeof(char));
printf("AFTER: %s\n", string);
system("PAUSE");
return 0;
}
The outpout is:
BEFORE: initi1l wording cont2ining forty-nine ch3r4cters.
AFTER: initi1l wording cont2inia
Notice it 'a' at the end of the string! I have no idea where this comes from, maybe somewhere in the heap. It is not from the original data block. Initially I was using realloc() with arrays of structures and it was obviously corrupting the data in more significant ways.
How can I work around this problem?

C strings require a NUL terminator. You're implicitly expecting realloc() to somehow figure out that the memory contains a C string, and replace its last character with NUL. It doesn't do this; you have to do it yourself:
string = (char *) realloc(string, 24*sizeof(char));
string[23] = 0; // <========= THE FIX
printf("AFTER: %s\n", string);
In other words, it's a bug in your code.

It does not! In C "String" is a set of character delimited with \0. In this case you try to print "string", therefore you get your original 24 characters and some tail until random \0 is found in memory

Strings in C are null terminated. I am surprised that the program did not crash.

It's character 25 and you have no 0-termination in the first 24.

Related

String operations cause segfault C [duplicate]

This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 1 year ago.
I'm trying to 'deep copy' a string so that I can perform operations on one copy, while retaining the original copy. This is the base example that I've got and for some reason the strncpy call causes a segfault. Please help
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
char* stringB = malloc(sizeof(char) * strlen(stringA));
printf("A: %s, B: %s\n", stringA, stringB);
for (int i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
printf("A: %s, B: %s\n", stringA, stringB);
strncpy(stringA, stringB, strlen(stringA) - 1);
printf("A: %s, B: %s\n", stringA, stringB);
}
Easiest fix is to make a local copy of that string literal:
char stringA[] = "someVeryinTeresTingString";
Everything else works just the same.
Note that in the original code you have a pointer to immutable memory, while in this version you have a local (stack) array that is initialized with a copy of that string.
Another thing to note is if you're copying and manipulating C strings, do things like this:
char* stringB = strdup(stringA);
for (int i = 0; i < strlen(stringB); ++i) {
stringB[i] = tolower(stringB[i]);
}
Or even more efficiently by avoiding all these expensive strlen() calls:
char* stringB = strdup(stringA);
for (char* p = stringB; *p; ++p) {
*p = tolower(*p);
}
This line:
char* stringB = malloc(sizeof(char) * strlen(stringA));
shuld be like this:
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
then you will able to copy the \0 in the end of stringA
also, you want to copy to literal string - that is segmentation fault
char *strncpy(char *dest, const char *src, size_t n)
I'll try to comment and correct in your own code the mistakes I've seen:
(I will not correct things that can be eliminated or better done in another way, but are correct or not harmful, so you'll see only what must be corrected because of programming errors, and not questions about style or programming uses)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
/* you need to consider the space for the final null character in the malloc() call */
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
/* you don't need to use sizeof(char) as it is always equal to one.
* Multiplying by one is not necessary, but you'll probably know.
* char is warranteed by C standard that its sizeof is one. */
/* you need to copy the string *before* printing, or you will print an
* uninitialized string. Or at least initialize stringB to zeros, so you can
* use it with printf like functions (I do initialize the first char position to
* zero to make it appear as a length zero "" string)
* You will incurr in undefined behaviour if you don't do this. */
stringB[0] = '\0';
printf("A: %s, B: %s\n", stringA, stringB);
/* you need to copy the strings, so you can do it better if you test when
* stringA[i] == '\0', so you don't calculate the length of a string that is
* not going to change at every loop iteration. I will not change your
* code, because this is not an error. But strlen() searches from the
* beginning of the string for the '\0' char, character by character,
* and this test is done at every loop iteration. With the expression
* stringA[i] == 0 you do only a test per loop iteration to see if
* the char at position i in stringA is the null character. */
int i;
for (i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
/* you have not copied the final '\0', so I do it now. I need to move the
* declaration of i outside of the loop to be able to use it's value. */
stringB[i] = 0; /* you can use 0 or '\0' interchangeably */
printf("A: %s, B: %s\n", stringA, stringB);
/* nope. you need to copy the strings with a normal strcpy() as you know that
* both are the same length (better, you know that the space in stringB
* is the same as the length of stringA plus one). If you do this, you will not copy the last '\0' char, so wee need to append it.
* well, I don't know if that is what you want, so I don't actually touch anything here. */
strncpy(stringA, stringB, strlen(stringA) - 1);
/* stringB should be one char shorter than stringA */
printf("A: %s, B: %s\n", stringA, stringB);
}
by the way, you have been recommended to use strdup(3). This is a good idea, you don't need to be thinking on final nulls in this case, because strdup() takes care of it. Just remember that strdup(3) is not included in many C standard revisions, so you can get in trouble if you
move your program to a place lacking it (that should be very strange, anyway)

Dereference C string pointer into variable

I have the following simple program which creates a pointer to the first character of a string:
char str[] = "Hello world";
char *p = &str[0];
How can I then get this string back into a variable using only the pointer?
Dereferencing the pointer just gives the first character of the string - as somewhat expected - so I'm assuming that there is no 'simple' way to achieve this and it will instead require writing extra code.
The current way I would approach this would be as follows:
Iterate from the pointer until a null terminator is reached to find the length of the string
Create a new char array with this length
Iterate through again inserting characters into this array
Is there a library function to achieve this, or if not, a simpler way that doesn't involve iterating twice?
Yes you have to "do it by hand". Because there are no objects in C - you need to take care of all that happens in the code.
You can use malloc, strlen and memcpy:
char str[] = "Hello world";
char *p = malloc(strlen(str) + 1);
if (!p) { abort(); }
memcpy(p, str, strlen(str) + 1);
You can use strcpy and forget about one strlen:
char *p = malloc(strlen(str) + 1);
if (!p) { abort(); }
strcpy(p, str);
Or you can use strdup from POSIX or a C extension:
char *p = strdup(str);
if (!p) { abort(); }
...
Is there a library function to achieve this, or if not, a simpler way that doesn't involve iterating twice?
As said in comment, strdup() will do exactly what you want. But here there is another problem (by your point of view): strcpy() will iterate the string twice, because there is no other way to duplicate a string.
By definition, strings in C are a sequence of characters somewhere in memory, with the last one character being a NUL (with single L), the value 0 (in a char). References to strings are pointers to the first character in the sequence depicted above. Note that two different strings can point to the same memory (they are not so different then...), or a string can point into the middle of another. These two cases are somewhat particular but not uncommon. The memory for strings must be managed by the programmer, who is the only one to know where allocate and deallocate space for strings; functions like strcpy() do nothing special in this regard, they are (presumably) well written and optimized, so maybe to copy a string the behavior is not plain as I depicted it before, but the idea is the same.
try this code:
#include "stdio.h"
int main(){
char str[] = "Hello world";
int count = 12;
char (*p)[12] = &str;
printf("%c\n",(*p)[0]);
printf("%c\n",(*p)[1]);
printf("%c\n",(*p)[2]);
printf("%c\n",(*p)[3]);
printf("%s\n",(*p));
}
Here's how I would make a copy of a string using only the standard library functions:
#include <stdio.h> // printf
#include <stdlib.h> // malloc
#include <string.h> // strcpy
int main(void)
{
char str[] = "Hello world"; // your original string
char *p = (char *)malloc(strlen(str) + 1); // allocate enough space to hold the copy in p
if (!p) { // malloc returns a NULL pointer when it fails
puts("malloc failed.");
exit(-1);
}
strcpy(p, str); // now we can safely use strcpy to put a duplicate of str into p
printf("%s\n", p); // print out this duplicate to verify
return 0;
}

Incorrect calculation by strlen for a string pointer?

#include <stdio.h>
#include <string.h>
int main()
{
char *str3;
str3="Final string.";
for(;*str3;)
{
printf("%c", *str3++);
}
printf("\n");
printf("%d bytes", strlen(str3));
return 0;
}
I've been confused about why the output says 0 bytes when it should be saying 13 bytes. I removed the for loop like so:
#include <stdio.h>
#include <string.h>
int main()
{
char *str3;
str3="Final string.";
printf("%d bytes", strlen(str3));
return 0;
}
and the output comes out correct saying 13 bytes. So I figured it had something to do with the for loop. My guess was: The loop reads through the contents but updates the variable as it goes along i.e. *str3++, once it's complete there's no data left to read and all the data that was already read is, well, read & gone (hehe)... which means 0 bytes?? Like reading a book and whiting out the last word you read.
If that's the case I'd have to refill it with data, do a repeat initialization by putting str3="Final string."; directly after the for loop and it'll show the correct output...but...I feel like that's a bad/cheap trick?
I'm not exactly sure what's happening. Please help.
Thanks in advance!!
Before for loop, str3 is pointing to:
str3
|
V
+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|F|i|n|a|l| |s|t|r|i|n|g|.|\0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
In for loop you are incrementing str3 in printf() till str3 hits null-character:
printf("%c", *str3++);
So, after for loop str3 is pointing to:
str3
|
V
+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|F|i|n|a|l| |s|t|r|i|n|g|.|\0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
strlen() determines the length of a string by terminating null-character. Since str3 is pointing to terminating null-character of string, hence you are getting the output 0.
You can take another pointer and point it to str3 and use it in for loop, like this:
#include <stdio.h>
#include <string.h>
int main()
{
char *str3, *tmp;
str3="Final string.";
tmp=str3;
for(;*tmp;)
{
printf("%c", *tmp++);
}
printf("\n");
printf("%zu bytes", strlen(str3));
return 0;
}
Output:
Final string.
13
Additional:
strlen() return type is size_t. You should use format specifier %zu for printing the strlen returned value.
You are incrementing the str pointer until it points to 0 (the end of the string) and when you call strlen(str3) it returns 0.
you are advancing the pointer to the start (initialization)of the string until it points to the end of the string. Hence when you call strlen on it you get size 0 - at that point it already points to the end of the string
you should use an auxillary pointer to iterate the string - advance it while iterating while the strlen command will be with the original str3
you can also add a counter in your for body and that will save you the need to call strlen at the end
in your case the string is literal and does not need to be freed, but when the strings are dynamically allocated working with an auxillary pointer is a must. - you must free allocated memory with the original pointer (returned from the allocation)

Segmentation fault (core dumped) using char*

i am new to c programming. i am getting Segmentation fault (core dumped) when i am
trying to print the string. please help.
#include <stdio.h>
#include <string.h>
int main()
{
char *ptr;
strcpy(ptr, "mystring");
printf( "%s\n", ptr);
return 0;
}
You haven't allocated any memory for your pointer to point at.
char array[MAX_LEN + 1];
char *ptr = array;
strncpy(ptr, "Cadence", MAX_LEN);
ptr[MAX_LEN] = '\0';
printf( "%s\n", ptr);
Please note that strncpy() can be a safer way to copy strings, since we specify the maximum number of characters to copy, which makes it harder to overrun the string and 'scribble' memory.
Update in response to comments: I've altered the above code to use a slightly safer pattern. You might also want to investigate strlcpy() (non-standard library).
When you declare char *ptr;, you allocate memory for a pointer to a char. But if you want to put a string inside the char, it will make an overflow.
Therefore, you have to allocate memory for your string :
char str[1024]; // which is the maximum string lenth that you will be able to put in str.
Furthemore, don't forget the null terminator (\0) that terminate every string and has the size of one char

garbage value when using malloc

I have to compare few characters of string say from 2nd char till 4th character( counting starts from zero)
The string is stored in elements of structure say zoopla->real
for example zoopla ->real has '447889036' where real is of type char real[20];
Also please note I cant use function strnstr.
The code works as expected but just for curiousity, I have added printf statement and it shows me value till 4th cahr and then some garabe characters.
I want to know why the printf statment is showing 2 extra garabe values?
char * copyTemp;
char *strptr;
copyTemp = (char *)malloc(sizeof(char)*6);
strncpy(copyTemp, zoopla->real, 5);
printf("the string copied is %s", copyTemp); // debug statemnt
strptr = strstr(copyTemp, "666");
if(strptr != NULL)
{
//some other function
}
else
//some other function
free(copyTemp);
All criticism and suggestions are welcome
It seems to me that copyTemp is not null terminated. That's why printf shows you garbage characters after the characters you put in there. It doesn't know where to stop so it continues iterate through memory.
Add
copyTemp[5] = '\0';
after strncpy.
See this example from the documentation of strncpy:
/* strncpy example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[]= "To be or not to be";
char str2[6];
strncpy (str2,str1,5);
str2[5]='\0';
puts (str2);
return 0;
}
see
http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
No null-character is implicitly appended to the end of destination, so destination will only be null-terminated if the length of the C string in source is less than num.
you have to add null your self.
if you will be allocating memory of constant size then use array only.
#include <stdio.h>
#include <string.h>
int main ()
{
char * copyTemp;
char *strptr;
copyTemp = (char *)calloc(sizeof(char),6);
strncpy(copyTemp, "88666782921", 5);
printf("the string copied is %s", copyTemp); // debug statemnt
strptr = strstr(copyTemp, "666");
if(strptr != NULL)
{
//some other function
}
else
//some other function
free(copyTemp);
return 0;
}
According to my old K&R, strncpy will only implicitly add null bytes if the source string has fewer characters than the number to be copied.
In this case, zoopla->real has more than 5 characters, so the function is simply copying the first five characters. Since you haven't initialized the memory to zero, or explicitly added a null byte, the string is not terminated after the fifth character. So when you print the string, you get additional bytes with essentially random values, until one is hit that happens to be zero.

Resources