I have two ways to do the same purpose, the first-way prints unknown symbols and the second-way prints exactly what I want.
The first-way:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1), *p = str;
while (*constStr) {
*p = *constStr;
constStr++;
p++;
}
printf("%s\n", str);
free(str);
The result:
The second-way:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1);
for (int i = 0; i <= strlen(constStr); i++) {
str[i] = constStr[i];
}
printf("%s\n", str);
free(str);
The result:
Why the first-way the result seems strange?
No you didn't null terminate the string. This is undefined behavior to pass pointer to non-null terminated char array in printf using %s format specifier.
Outside the loop make *p=0. That will null terminate the char array.
Second way is printing because you copied the \0 which is in strlen(constStr) index of the array. Notice the <= in the loop condition.
From where those weird letters come?
Think in terms of printf. When it sees the %s format specifier it prints starting from the address provided to it as argument. Now when does it stop? when it finds the \0. here it didnt find it and it read out of the memory that you allocated. Those bit patterns on those memory turned out to be those non printable characters. That's what you saw. The correct way to do this would be:
const char *constStr = "Hello world";
char *str = malloc(strlen(constStr) + 1), *p = str;
while (*p++ = *constStr++); // here `\0` will be copied.
printf("%s\n", str);
free(str);
When working with strings make sure you keep the corner cases clean. By that I mean,check whether the \0 is copied or not etc. This is so common a problem when we implement string routines.
To fix the first one, add a null at the end of the string:
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr) + 1), *p = str;
while (*constStr) {
*p = *constStr;
constStr++;
p++;
}
*p = '\0'; /* <-- HERE */
printf("%s\n", str);
free(str);
Note: you are modifying a pointer to a temporary - not recommended. Use the same approach as you did for str, by using a another pointer which gets shifted.
Related
How can I add '.' to the char Array := "Hello World" in C, so I get a char Array: "Hello World." The Question seems simple but I'm struggling.
Tried the following:
char str[1024];
char tmp = '.';
strcat(str, tmp);
But it does not work. It shows me the error: "passing argument 2 of ‘strcat’ makes pointer from integer without a cast"
I know that in C a char can be cast as int aswell. Do I have to convert the tmp to an char array aswell or is there a better solution?
strcat has the declaration:
char *strcat(char *dest, const char *src)
It expects 2 strings. While this compiles:
char str[1024] = "Hello World";
char tmp = '.';
strcat(str, tmp);
It will cause bad memory issues because strcat is looking for a null terminated cstring. You can do this:
char str[1024] = "Hello World";
char tmp[2] = ".";
strcat(str, tmp);
Live example.
If you really want to append a char you will need to make your own function. Something like this:
void append(char* s, char c) {
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
append(str, tmp)
Of course you may also want to check your string size etc to make it memory safe.
The error is due the fact that you are passing a wrong to strcat(). Look at strcat()'s prototype:
char *strcat(char *dest, const char *src);
But you pass char as the second argument, which is obviously wrong.
Use snprintf() instead.
char str[1024] = "Hello World";
char tmp = '.';
size_t len = strlen(str);
snprintf(str + len, sizeof str - len, "%c", tmp);
As commented by OP:
That was just a example with Hello World to describe the Problem. It
must be empty as first in my real program. Program will fill it later.
The problem just contains to add a char/int to an char Array
In that case, snprintf() can handle it easily to "append" integer types to a char buffer too. The advantage of snprintf() is that it's more flexible to concatenate various types of data into a char buffer.
For example to concatenate a string, char and an int:
char str[1024];
ch tmp = '.';
int i = 5;
// Fill str here
snprintf(str + len, sizeof str - len, "%c%d", str, tmp, i);
In C/C++ a string is an array of char terminated with a NULL byte ('\0');
Your string str has not been initialized.
You must concatenate strings and you are trying to concatenate a single char (without the null byte so it's not a string) to a string.
The code should look like this:
char str[1024] = "Hello World"; //this will add all characters and a NULL byte to the array
char tmp[2] = "."; //this is a string with the dot
strcat(str, tmp); //here you concatenate the two strings
Note that you can assign a string literal to an array only during its declaration.
For example the following code is not permitted:
char str[1024];
str = "Hello World"; //FORBIDDEN
and should be replaced with
char str[1024];
strcpy(str, "Hello World"); //here you copy "Hello World" inside the src array
I think you've forgotten initialize your string "str": You need initialize the string before using strcat. And also you need that tmp were a string, not a single char. Try change this:
char str[1024]; // Only declares size
char tmp = '.';
for
char str[1024] = "Hello World"; //Now you have "Hello World" in str
char tmp[2] = ".";
Suggest replacing this:
char str[1024];
char tmp = '.';
strcat(str, tmp);
with this:
char str[1024] = {'\0'}; // set array to initial all NUL bytes
char tmp[] = "."; // create a string for the call to strcat()
strcat(str, tmp); //
I have a chunk of memory I'm declaring on the heap.
char *str;
str = (char *)malloc(sizeof(char) * 10);
I have a const string.
const char *name = "chase";
Because *name is shorter than 10 I need to fill str with chase plus 5 spaces.
I've tried to loop and set str[i] = name[i] but there's something I'm not matching up because I cannot assign spaces to the additional chars. This was where I was going, just trying to fill str with all spaces to get started
int i;
for (i = 0; i < 10; i++)
{
strcpy(str[i], ' ');
printf("char: %c\n", str[i]);
}
As the others pointed out, you need
//malloc casting is (arguably) bad
str = malloc(sizeof(char) * 11);
and then, just do
snprintf(str, 11, "%10s", name);
Using snprintf() instead of sprintf() will prevent overflow, and %10swill pad your resulting string as you want.
http://www.cplusplus.com/reference/cstdio/snprintf/
If you want str to have 10 characters and still be a C-string, you need to '\0' terminate it. You can do this by mallocing str to a length of 11:
str = malloc(11);
Note there's no need to cast the return pointer of malloc. Also, sizeof(char) is always 1 so there's no need to multiply that by the number of chars that you want.
After you've malloc as much memory as you need you can use memset to set all the chars to ' ' (the space character) except the last element. The last element needs to be '\0':
memset(str, ' ', 10);
str[10] = '\0';
Now, use memcpy to copy your const C-string to str:
memcpy(str, name, strlen(name));
easy to use snprintf like this
#include <stdio.h>
#include <stdlib.h>
int main(){
char *str;
str = (char *)malloc(sizeof(char)*10+1);//+1 for '\0'
const char *name = "chase";
snprintf(str, 11, "%-*s", 10, name);//11 is out buffer size
printf(" 1234567890\n");
printf("<%s>\n", str);
return 0;
}
This is purely for self-interest and is not a homework assignment.
#include <stdio.h>
int main(void)
{
char* str3;
char* str1 = "Hello";
char* str2 = "World!";
while(*str1) str1++;
while(*str1++ = *str2++);
return 0;
}
I am attempting to develop a better understanding of C pointers and in doing so I would like to concatenate two strings and place the result into a third string. The (incomplete) code above results in a segfault and I'm not sure why. Isn't it possible to loop over the value referenced by a pointer and copy the data to another address?
Edit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char* str1 = "Hello";
char* str2 = "World!";
char *str3 = malloc(strlen(str1) + strlen(str2) + 1);
while(*str1) *str3++ = *str1++;
while(*str2) *str3++ = *str2++;
puts(str3);
return 0;
}
The new attempt is above, and while not functional, are there "obvious" items I need to fix?
while(*str1) str1++;
This advances str1 until it points to the terminating zero byte at the end of the string constant.
while(*str1 = *str2++);
This modifies the terminating zero byte at the end of the string, but the string is a constant and so can't be modified.
If you want to assemble a string in memory, you need to allocate some space to do that in or use functions that do so. You could do:
char *new_string = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(new_string, str1);
strcat(new_string, str2);
The first line allocates enough space to hold str1's contents, str2's contents, and the terminating zero byte.
int main(void)
{
char* str1 = "Hello";
char* str2 = "World!";
// allocate one more byte for string terminate cher ('\n')
int size = strlen(str1) + strlen(str2);
char* str3 = (char*)malloc(size + 1);
char* str_mod = str3;
while( (*str_mod++ = *str1++) != '\0');
str_mod--;
while( (*str_mod++ = *str2++) != '\0');
printf ( "%s", str3);
free (str3);
return 0;
}
The constant strings are not modifyable. You are not modifying str3.
You need to
get the length of str1 and str2.
malloc length of str1 + length str2 + 1 and assign to str3
You can use while loops if you like for the copy, or you can use strcpy and strcat to copy the strings to str3.
Since you are trying to learn, I am trying not to write the code for you.
int main (void){
char* str1 = "Hello";
char* str2 = "World";
int size1 = strlen(str1);
int size2 = strlen(str2);
int i = 0;
char* out = malloc(sizeof(char)*(size1+size2)+1);
for (i = 0; i < size1; i++){
out[i] = str1[i];
}
for (i = 0; i < size2; i++){
out[i+size1] = str2[i];
}
out[strlen(out)-1] = \0;
//out is a string.
//dont forget to free when you are done. free(out);
}
Its been a few months since i did C, but this would work. my syntax might be slightly off.
2nd attempt in question misses putting string terminating null to end of str3. So puts reads beyond end of data, prints garbage and may even crash if there is no 0 byte before reading invalid address. Add *str3 ='\0'; after loops.
Additionally, you modify str3 and lose start of string. Add one more variable, keep the pointer returned by malloc, and pass that to puts. Current code will start printing at the end of the new string.
Then when you have pointers to string literals, make them pointers to const char, because usually string literals are in read only memory area:
const char* str1 = "Hello";
const char* str2 = "World!";
I'm writing a hex-to-base64 encoder as an exercise, since I'm new to C. Nevermind why the code isn't working the way I want it to, why am I getting these carat-letter combos next to my output?
const char * hex_to_base64(const char * s) {
int i;
for(i = 0; i < strlen(s)/3; i = i + 3) {
char str[3];
str[0] = s[i];
str[1] = s[i+1];
str[2] = s[i+2];
printf("%s\n", str);
}
return NULL;
}
int main() {
const char * x = "4453def6d206b696c6c696e6720796f757220627261696e206c696b652061222226f789436f6e6f5573206dabb7368726fa4b2";
hex_to_base64(x);
return 0;
}
And I'm getting this output:
445
3de^C
f6d^F
206
b69^L
6c6^O
c69^R
6e6^U
720^X
796^[
f75^^
722!
Could someone explain why I am getting the carat-letter combos at the end of printf?
You're passing a non-zero-terminated string to printf(). Change:
char str[3];
to
char str[4];
str[3] = '\0';
Even better, move the declaration and zero-assignment outside the loop.
char str[3];
str[0] = s[i];
str[1] = s[i+1];
str[2] = s[i+2];
printf("%s\n", str);
str should be null-terminated. You have to change str declaration to:
char str[4] = {0};
Other people have already pointed out the bugs in your program, but your question was "why I am getting the carat-letter combos", and the answer to that is that the caret-letter combinations are your terminal's representation of various non-printing characters that you are attempting to print (due to the aforementioned bugs).
I have two strings, e.g.:
str1 = "aaabbbcccdddeee"
str2 = "aaabbbccc"
How to do something like str1 - str2 to get the dddeee substring?
If str2 is guaranteed to be a prefix of str1, then this will suffice:
const char *str3 = &str1[strlen(str2)];
which is equivalent to this: (as #James points out in the comments)
const char *str3 = str1 + strlen(str2);
Of course, str3 is just a pointer into one of the original strings. If the contents of the original string changes, then so will your result. So you may want to create a copy, using malloc() and strcpy() (and then free() at some point).
This will skip the common prefix of two strings:
char* suffix(const char* prefix, const char* str) {
while (*prefix && *str && *prefix == *str) {
prefix++;
str++;
}
return str;
}
For example, if you pass "AAB" and "AACC", this would return "CC".
str3 will contain a copy of the prefix:
str1 = "aaabbbcccdddeee"
str2 = "aaabbbccc"
size_t length = strlen1 - strlen2;
char* str3 = calloc(sizeof(char), length + 1);
memcpy(str3, str1+strlen(str2), length);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char a[] = "aaaabbbbbdddeee";
char b[] = "aaaabbbbb";
const char* start = strstr(a, b);
if (start)
{
printf("%s\n", a + strlen(b));
}
return 0;
}
Since you have clarified that str2 is a prefix of str1, you can get the pointer to the extra part in str2 simply with the operation:
str1 + strlen(2);
For example, to print the "dddeee" part of your string:
printf("%s\n", str1 + strlen(str2));
How this works is simple. str1 + strlen(str2) is a pointer that is strlen(str2) N characters away from the beginning of the string pointed to be str1. strlen(str2) returns the number of characters in the second string and you skip those many characters in the first string and reach the extra part.