I have a function in C where i am trying to get strings from two different locations (unknown size, could be quiet large) and combine them into one string and return them. If i just print the two strings then I get the correct result, but when I try to combine the strings using strcat I end up with 5 garbage characters and then the result of the combined strings.
Anyone have some advice as to what I am doing wrong? Here is some sample code to demonstrate what I am doing:
static int get_information(char** results)
{
size_t s1_length;
size_t s2_length;
/* DEBUGGING - Prints the correct string */
printf(get_string_1());
printf(get_string_2());
printf("\n");
/* Allocate memory for new string */
s1_length = strlen(get_string_1());
s2_length = strlen(get_string_2());
*results = malloc(sizeof(char) * (dir_length + file_length));
if(results == NULL)
return -1;
/* Combine the strings */
strcat(*results, get_string_1());
strcat(*results, get_string_2());
/* DEBUGGING - prints 5 garbage characters then the correct string */
printf(*results);
printf("\n");
return 0;
}
strcat needs to find the null terminator in the destination. Your *result points to uninitialised memory, which happens to have a null terminator 5 characters in.
Adding *result[0]='\0'; just before combining the strings should fix it.
Also, you are not allocating enough space for the null terminator in *result.
Why do you strcat the first string? Simply copy it. Otherwise it will append to whatever garbage is in the uninitialized memory ...
/* Combine the strings */
strcpy(*results, get_string_1());
strcat(*results, get_string_2());
strcat() assumes the destination to be a valid string, so make it so by adding
*results[0] = '\0';
before you do strcat()
Alternatively try doing these:
strcpy(*results, get_string_1());
strcat(*results, get_string_2());
Lastly, what exactly is happening in this line:
*results = malloc(sizeof(char) * (dir_length + file_length));
Make sure you allocate enough space to results. Ideally it should be:
*results = malloc(sizeof(char) * (s1_length+s2_length+1));
for allocating enough space as s1 and s2 and followed by a terminating '\0' character.
Related
I'm building a rocket for Elon Musk and the memory usage is very important to me.
I have text and a pointer to it pText. It's chilling in the heap.
Sometimes I need to analyse the string, its words. I don't store substrings in heap, instead I store two pointers start/end for represeting a substring of the text. But sometimes I need to print those substrings for debugging purposes. How do I do that?
I know that for a string to be printed I need two things
a pointer to the begging
null terminator at the end
Any ideas?
// Text
char *pText = "We've sold the Earch!";
// Substring `sold`
char *pStart = &(pText + 6) // s
char *pEnd = &(pStart + 3) // d
// Print that substring
printf("sold: %s", ???);
If you only want to print the sub-string, then use a precision argument for printf:
printf("sold: %.*s", (int) (pEnd - pStart) + 1, pStart);
If you need to use the sub-string in other ways then the simplest is probably to create a temporary string, copy into it, and then print that instead.
Perhaps something like this:
// Get the length of the sub-string
size_t length = pEnd - pStart + 1;
// Create an array for the sub-string, +1 for the null-terminator
char temp[length + 1];
// Copy the sub-string
memcpy(temp, pStart, length);
// Terminate it
temp[length] = '\0';
If you need to do this many times I recommend you create a generic function for this.
You might also need to dynamically allocate the string using malloc depending on use-case.
I'm facing an issue connected with printing one char from string in c.
The function takes from users two variables - number (number which should print character from string) and string. When I put as a string "Martin" and number is 5 then the output is "i". But when the number is larger than the string length something goes wrong and I actually don't know what's wrong.
PS. If the number is longer than string size it should print "Nothing".
void printLetter() {
char * string = (char*)malloc(sizeof(char));
int n;
printf("Number:\n");
scanf("%i", &n);
printf("String:\n");
scanf("%s", string);
if(n > strlen(string)) {
printf("nothing");
} else {
printf("%c\n", string[n+1]);
}
free(string);
}
There is no need for dynamic allocation here, since you do not know the length of the string in advance, so just do:
void printLetter() {
char string[100]; // example size 100
...
scanf("%99s", string); // read no more than your array can hold
}
A fun exercise would be to count the length of the string, allocate dynamically exactly as mush space as you need (+1 for the null terminator), copy string to that dynamically allocated space, use it as you wish, and then free it.
Moreover this:
printf("%c\n", string[n+1]);
should be written as this:
printf("%c\n", string[n-1]);
since you do not want to go out bounds of your array (and cause Undefined Behavior), or print two characters next of the requested character, since when I ask for the 1st character, you should print string[0], when I ask for the 2nd, you should print string[1], and so on. So you see why we need to print string[n-1], when the user asks for the n-th letter.
By the way, it's common to use a variable named i, and not n as in your case, when dealing with an index. ;)
In your code, this:
char * string = malloc(sizeof(char));
allocates memory for just one character, which is no good, since even if the string had one letter only, where would you put the null terminator? You know that strings in C should (almost) always be NULL terminated.
In order to allocate dynamically memory for a string of size N, you should do:
char * string = malloc((N + 1) * sizeof(char));
where you allocate space for N characters, plus 1 for the NULL terminator.
Couple of problems...
sizeof(char) is generally 1 byte. Hence malloc() is allocating only one byte of memory to string. Perhaps a larger block of memory is required? "Martin", for example, will require at least 6 bytes, plus the string termination character (seven bytes total).
printf("%c\n", string[n+1]) is perhaps not quite right...
String: Martin\0
strlen= 6
Offset: 0123456
n = 5... [n+1] = 6
The character being output is the string terminator '\0' at index 6.
This might work better:
void printLetter() {
char * string = malloc(100 * sizeof(char));
int n;
printf("Number:\n");
scanf("%i", &n);
printf("String:\n");
scanf("%s", string);
if(n > strlen(string)) {
printf("nothing");
} else {
printf("%c\n", string[n-1]);
}
free(string);
}
You are facing buffer overflow.
Take a look to this question, so it will show you how to manage your memory properly in such situation: How to prevent scanf causing a buffer overflow in C?
Alternatively you can ask for number of letter and allocate only that much memory + 1. Then fgets(string, n,stdin); because you don't need rest of the string :-)
I'm using the code below to add some "0" chars into my string, but it seems there is a problem and the program will crash. Everything seems logic but I do not know where is the problem?
#include <stdlib.h>
#include <string.h>
int main()
{
char *Ten; int i=0; Ten = malloc(12);
Ten="1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
You declare Ten as a pointer to a string literal. However, you cannot rely on being able to modify a string literal, and thus the program crashes.
To fix this, you can declare Ten as an array instead:
int main()
{
char Ten[12]="1"; int i=0;
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
return 0;
}
Note that you need 12 bytes; 11 for the characters and one for the terminating NUL character.
Ten is a string literal and you cannot modify it. Try with array instead
char Ten[12] = "1";
for (i=0;i<10;i++)
strcat(Ten,"0");
printf("%s",Ten);
notice that I created an array of 12 characters, because there should be room for a termination '\0'.
You actually don't need strcat here, it's just do this
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
for (i = 1 ; i < 11 ; i++)
Ten[i] = '0';
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
or
char Ten = malloc(12);
if (Ten != NULL)
{
Ten[0] = '1';
memset(Ten + 1, '0', 10);
Ten[11] = '\0';
/* Use Ten here, for example printf it. */
printf("%s",Ten);
/* You should release memory. */
free(Ten);
}
To quote from strcat manual on linux:
The strcat() function appends the src string to the dest string,
overwriting the terminating null byte ('\0') at the end of dest, and
then adds a terminating null byte. The strings may not overlap, and
the dest string must have enough space for the result. If dest is not
large enough, program behavior is unpredictable; buffer overruns are
a favorite avenue for attacking secure programs.
Your Ten array is only long enough to store original literal. You need to preallocate memory as long as final desired string.
String literals might be stored in read only section of memory. Any attempt to modify such a literal causes undefined behavior.
To concatenate two strings, the destination must have enough space allocated for the characters to be added and space for '\0'. Change the declaration of Ten to
char Ten[12] = "1";
and it will work.
I have a program that reads the content of a file and saves it into buf. After reading the content it is supposed to copy two by two chars to an array. This code works fine if I'm not trying to read from a file but if I try to read it from a file the printf from buffer prints the two chars that I want but adds weird characters. I've confirmed and it's saving correctly into buf, no weird characters there. I can't figure out what's wrong... Here's the code:
char *buffer = (char*)malloc(2*sizeof(char));
char *dst = buffer;
char *src = buf;
char *end = buf + strlen(buf);
char *baby = '\0';
while (src<= end)
{
strncpy(dst, src, 2);
src+= 2;
printf("%s\n", buffer);
}
(char*)malloc(2*sizeof(char)); change to malloc(3*sizeof*buffer); You need an additional byte to store the terminating null character which is used to indicate the end-of-string. Aslo, do not cast the return value of malloc(). Thanks to unwind
In your case, with strncpy(), you have supplied n as 2, which is not having any scope to store the terminating null byte. without the trminating null, printf() won't be knowing where to stop. Now, with 3 bytes of memory, you can use strcpy() to copy the string properly
strncpy() will not add the terminating null itself, in case the n is equal to the size of supplied buffer, thus becoming very very unreliable (unlike strcpy()). You need to take care of it programmatically.
check the man page for strncpy() and strcpy() here.
I'm coding a program that takes some files as parameters and prints all lines reversed. The problem is that I get unexpected results:
If I apply it to a file containing the following lines
one
two
three
four
I get the expected result, but if the file contains
september
november
december
It returns
rebmetpes
rebmevons
rebmeceds
And I don't understand why it adds a "s" at the end
Here is my code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void reverse(char *word);
int main(int argc, char *argv[], char*envp[]) {
/* No arguments */
if (argc == 1) {
return (0);
}
FILE *fp;
int i;
for (i = 1; i < argc; i++) {
fp = fopen(argv[i],"r"); // read mode
if( fp == NULL )
{
fprintf(stderr, "Error, no file");
}
else
{
char line [2048];
/*read line and reverse it. the function reverse it prints it*/
while ( fgets(line, sizeof line, fp) != NULL )
reverse(line);
}
fclose(fp);
}
return (0);
}
void reverse(char *word)
{
char *aux;
aux = word;
/* Store the length of the word passed as parameter */
int longitud;
longitud = (int) strlen(aux);
/* Allocate memory enough ??? */
char *res = malloc( longitud * sizeof(char) );
int i;
/in this loop i copy the string reversed into a new one
for (i = 0; i < longitud-1; i++)
{
res[i] = word[longitud - 2 - i];
}
fprintf(stdout, "%s\n", res);
free(res);
}
(NOTE: some code has been deleted for clarity but it should compile)
You forget to terminate your string with \0 character. In reversing the string \0 becomes your first character of reversed string. First allocate memory for one more character than you allocated
char *res = malloc( longitud * sizeof(char) + 1);
And the try this
for (i = 0; i < longitud-1; i++)
{
res[i] = word[longitud - 2 - i];
}
res[i] = '\0'; // Terminating string with '\0'
I think I know the problem, and it's a bit of a weird issue.
Strings in C are zero terminated. This means that the string "Hi!" in memory is actually represented as 'H','i','!','\0'. The way strlen etc then know the length of the string is by counting the number of characters, starting from the first character, before the zero terminator. Similarly, when printing a string, fprintf will print all the characters until it hits the zero terminator.
The problem is, your reverse function never bothers to set the zero terminator at the end, which it needs to since you're copying characters into the buffer character by character. This means it runs off the end of your allocated res buffer, and into undefined memory, which just happened to be zero when you hit it (malloc makes no promises of the contents of the buffer you allocate, just that it's big enough). You should get different behaviour on Windows, since I believe that in debug mode, malloc initialises all buffers to 0xcccccccc.
So, what's happening is you copy september, reversed, into res. This works as you see, because it just so happens that there's a zero at the end.
You then free res, then malloc it again. Again, by chance (and because of some smartness in malloc) you get the same buffer back, which already contains "rebmetpes". You then put "november" in, reversed, which is slightly shorter, hence your buffer now contains "rebmevons".
So, the fix? Allocate another character too, this will hold your zero terminator (char *res = malloc( longitud * sizeof(char) + 1);). After you reverse the string, set the zero terminator at the end of the string (res[longitud] = '\0';).
there are two errors there, the first one is that you need one char more allocated (all chars for the string + 1 for the terminator)
char *res = malloc( (longitud+1) * sizeof(char) );
The second one is that you have to terminate the string:
res[longitud]='\0';
You can terminate the string before entering in the loop because you know already the size of the destination string.
Note that using calloc instead of malloc you will not need to terminate the string as the memory gets alreay zero-initialised
Thanks, it solved my problem. I read something about the "\0" in strings but wasn't very clear, which is now after reading all the answers (all are pretty good). Thank you all for the help.