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).
Related
I'm attempting to remove a character from a string in C. The problem I am having with my code is that it removes the first instance of the character from the string but also wipes everything after that character in the string too. For example, removing 'l' from 'hello' prints 'he' rather than 'heo'
int i;
char str1[30] = "Hello", *ptr1, c = 'l';
ptr1 = str1;
for (i=0; i<strlen(str1); i++)
{
if (*ptr1 == c) *ptr1 = 0;
printf("%c\n", *ptr1);
ptr1++;
}
I need to use pointers for this and would like to keep it as simple as possible since I'm a beginner in C.
Thanks
You can do it like this:
void remove_all_chars(char* str, char c) {
char *pr = str, *pw = str;
while (*pr) {
*pw = *pr++;
pw += (*pw != c);
}
*pw = '\0';
}
int main() {
char str[] = "llHello, world!ll";
remove_all_chars(str, 'l');
printf("'%s'\n", str);
return 0;
}
The idea is to keep a separate read and write pointers (pr for reading and pw for writing), always advance the reading pointer, and advance the writing pointer only when it's not pointing to a given character.
If you remove the characters in place you will have to shift the rest of the string one place to the left every time you remove a character, this is not very efficient. The best way is to have a second array that takes the filtered string. For example you can change your code like this.
int i;
char str1[30] = "Hello", *ptr1, c = 'l';
char str2[30] = {0}, *ptr2;
ptr1 = str1;
ptr2 = str2;
for (i=0; i<strlen(str1); i++)
{
if (*ptr1 != c) *ptr2++=*ptr1;
ptr1++;
}
printf("%s\n", str2);
The problem is that when you encounter the first character that matches c, you insert a null character right there. That means you're essentially cutting off the rest of the string.
What you need to do is when you find a matching character, move the following characters back one position. Then you need to insert the null character at the very end depending on how many characters you have removed.
char str1[30] = "Hello", *prt1, c = 'l';
char str2[30], *prt2;
prt1 = str1;
prt2 = str2;
while(*prt1 != 0)
{
if(*prt1 != c)
{
*prt2 = *prt1;
prt2++;
}
prt1++;
}
*prt2 = '\0';
i know that it is a type of duplicate answer, but this code is function's version for solving the problem. I thought that as the questioner was a beginner, he might learn much from decomposed version of problem.
int del_x_char(char *p, int x)
{
char *q;
x=first_occurance(p, 'i')/*you can replace any character that you want delete with 'i'*/
q=p+x;
while(*q=*(q+1))
q++;
*q='\0';
return 0;
}
int first_occurance(char *q, char phar)
{
int i=0;
while(*q)
{
if(*q++==phar)
return i;
i++;
}
return -1;
}
just change
if (*ptr1 == c) *ptr1 = 0;
to
if (*ptr1 == c) continue;
as #ouah said, it breaks at the first NULL character..
C defines a string as "a contiguous sequence of characters terminated by and including the first null character"
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.
I'm fairly new to C and I'm trying to work out dynamic memory allocation for reading from a file. At least I think that's what I'm doing.
Anyway, this code works:
int readfromfile(FILE *filepointer)
{
size_t size = 2;
char *str = (char *) malloc(sizeof(char));
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
str = (char *) realloc(str, size);
str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", str);
free(str);
return 0;
}
And this code does not:
int main()
{
char *str = (char *) malloc(sizeof(char));
...
readfromfile(ifpointer, &str);
}
int readfromfile(FILE *filepointer, char **str)
{
size_t size = 2;
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
*str = (char *) realloc(*str, size);
*str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", *str);
free(str);
return 0;
}
I cannot understand why because as far as I understand I'm sending a pointer to the location of the char array to the function and accessing the data everytime. The compilers shows no error messages, it just loops through once and on the second loop crashes after the realloc every time. The character assigned to the first value is garbage too.
I have spent an age trying to get this to worked and done a lot of research so I apologise if I've missed a solution but I'm truly stuck at this point.
You get a crash because
*str[counter] = (char) character;
is the same as
*(str[counter]) = (char) character;
as opposed to
(*str)[counter] = (char) character;
which is actually what you wanted. Read Operator Precedence on Wikipedia. You'll find that [] has more precedence than the * (dereference operator).
Also, the cast here, as well as in the calls to realloc and malloc, is unnecessary. Don't forget to check the return value of realloc, malloc etc to see if they were successful in allocating memory.
Now, you have another problem: free(str); in the second code should be free(*str);. Note that after *str has been freed from the function, you aren't supposed to read or write into this memory location from main as it has now become invalid for you to tamper with.
in your int readfromfile(FILE *filepointer, char **str) the parameter char **str is actually the same as char *str[], which means **str is expecting an array of char pointers. however you're passing to it char *str which is just an array of char
when you use readfromfile(...) you should do it this way (something like...):
char *str[2] = {"some char array", "another char array"};
readfromfile(ifpointer, str);
or:
char *a = "this char array";
char **str = &a[0];
readfromfile(ifpointer, str);
you'll get the idea...
I'm having probs with an own function that should make str2 copied to str1 based on the amount of characters.
char * strncpy_own(char * str1, char * str2, int c)
{
int i;
for( i = 0; i < c; i++, str1++, str2++ )
{
*str1 = *str2;
}
*(str1 + 1) = '\0';
return str1;
}
Please help, When it starts it immediately terminates and says: CLearningsss has stopped working ( my name of the project ).
It should be
*str1 = '\0';
since it has already been incremented.
In a simplified version
while (c-- > 0) *str1++ = *str2++;
you can easily see that when c is 1, *str1 gets *str2 value, and is incremented, thus str1 is pointing after the value that has just been set. Thus using directly str1 pointer to set the final 0 to indicate the end of the string can be written as
while (c-- > 0) *str1++ = *str2++;
*str1 = 0;
(actually '\0' represents a char value of zero, thus writing directly 0 works as well)
Also, (thanks to #Guillaume_Morin for mentioning that) the function should better return a pointer to the beginning of the result string (str1), and you need to keep a copy of the initial str1 for that, since it is incremented later on:
char * strncpy_own(char * str1, char * str2, int c) {
char *str1copy = str1;
while (c-- > 0) *str1++ = *str2++;
*str1 = 0;
return str1copy;
}
Did you allocate the memory for str1 and str2 in advance? You need c + 1 bytes for each string; c + 2 for the mutated string given the bug you have that another answer has pointed out;-)
char *strncpy_my(char *str1, char *str2, size_t size){
char *ret = str1;
while(size>0){
if(*str2=='\0')break;
*str1++ = *str2++;
--size;
}
while(size>0){
*str1++ = '\0';
--size;
}
return ret;
}
I'm attempting to remove a character from a string in C. The problem I am having with my code is that it removes the first instance of the character from the string but also wipes everything after that character in the string too. For example, removing 'l' from 'hello' prints 'he' rather than 'heo'
int i;
char str1[30] = "Hello", *ptr1, c = 'l';
ptr1 = str1;
for (i=0; i<strlen(str1); i++)
{
if (*ptr1 == c) *ptr1 = 0;
printf("%c\n", *ptr1);
ptr1++;
}
I need to use pointers for this and would like to keep it as simple as possible since I'm a beginner in C.
Thanks
You can do it like this:
void remove_all_chars(char* str, char c) {
char *pr = str, *pw = str;
while (*pr) {
*pw = *pr++;
pw += (*pw != c);
}
*pw = '\0';
}
int main() {
char str[] = "llHello, world!ll";
remove_all_chars(str, 'l');
printf("'%s'\n", str);
return 0;
}
The idea is to keep a separate read and write pointers (pr for reading and pw for writing), always advance the reading pointer, and advance the writing pointer only when it's not pointing to a given character.
If you remove the characters in place you will have to shift the rest of the string one place to the left every time you remove a character, this is not very efficient. The best way is to have a second array that takes the filtered string. For example you can change your code like this.
int i;
char str1[30] = "Hello", *ptr1, c = 'l';
char str2[30] = {0}, *ptr2;
ptr1 = str1;
ptr2 = str2;
for (i=0; i<strlen(str1); i++)
{
if (*ptr1 != c) *ptr2++=*ptr1;
ptr1++;
}
printf("%s\n", str2);
The problem is that when you encounter the first character that matches c, you insert a null character right there. That means you're essentially cutting off the rest of the string.
What you need to do is when you find a matching character, move the following characters back one position. Then you need to insert the null character at the very end depending on how many characters you have removed.
char str1[30] = "Hello", *prt1, c = 'l';
char str2[30], *prt2;
prt1 = str1;
prt2 = str2;
while(*prt1 != 0)
{
if(*prt1 != c)
{
*prt2 = *prt1;
prt2++;
}
prt1++;
}
*prt2 = '\0';
i know that it is a type of duplicate answer, but this code is function's version for solving the problem. I thought that as the questioner was a beginner, he might learn much from decomposed version of problem.
int del_x_char(char *p, int x)
{
char *q;
x=first_occurance(p, 'i')/*you can replace any character that you want delete with 'i'*/
q=p+x;
while(*q=*(q+1))
q++;
*q='\0';
return 0;
}
int first_occurance(char *q, char phar)
{
int i=0;
while(*q)
{
if(*q++==phar)
return i;
i++;
}
return -1;
}
just change
if (*ptr1 == c) *ptr1 = 0;
to
if (*ptr1 == c) continue;
as #ouah said, it breaks at the first NULL character..
C defines a string as "a contiguous sequence of characters terminated by and including the first null character"