Replacing spaces with %20 in C - c

I am writing a fastcgi application for my site in C. Don't ask why, leave all that part.
Just help me with this problem- I want to replace spaces in the query string with %20.
Here's the code I'm using, but I don't see 20 in the output, only %. Where's the problem?
Code:
unsigned int i = 0;
/*
* Replace spaces with its hex %20
* It will be converted back to space in the actual processing
* They make the application segfault in strtok_r()
*/
char *qstr = NULL;
for(i = 0; i <= strlen(qry); i++) {
void *_tmp;
if(qry[i] == ' ') {
_tmp = realloc(qstr, (i + 2) * sizeof(char));
if(!_tmp) error("realloc() failed while allocting string memory (space)\n");
qstr = (char *) _tmp;
qstr[i] = '%'; qstr[i + 1] = '2'; qstr[i + 2] = '0';
} else {
_tmp = realloc(qstr, (i + 1) * sizeof(char));
if(!_tmp) error("realloc() failed while allocating string memory (not space)\n");
qstr = (char *) _tmp;
qstr[i] = qry[i];
}
}
In the code, qry is char *, comes as a actual parameter to the function.
I tried with i + 3, 4, 5 in realloc() in the space replacer block, no success.

String-handling in C can be tricky. I'd suggest going through the string first, counting the spaces, and then allocating a new string of the appropriate size (original string size + (number of spaces * 2)). Then, loop through the original string, maintaining a pointer (or index) to the position in both the new string and the original one. (Why two pointers? Because every time you encounter a space, the pointer into the new string will get two characters ahead of the pointer into the old one.)
Here's some code that should do the trick:
int new_string_length = 0;
for (char *c = qry; *c != '\0'; c++) {
if (*c == ' ') new_string_length += 2;
new_string_length++;
}
char *qstr = malloc((new_string_length + 1) * sizeof qstr[0]);
char *c1, *c2;
for (c1 = qry, c2 = qstr; *c1 != '\0'; c1++) {
if (*c1 == ' ') {
c2[0] = '%';
c2[1] = '2';
c2[2] = '0';
c2 += 3;
}else{
*c2 = *c1;
c2++;
}
}
*c2 = '\0';

qstr[i] = '%'; qstr[i + 1] = '2'; qstr[i + 2] = '0';
That line writes three characters to your output buffer, so the next character you write needs to be written at qstr[i+3]. However, you only step i by 1, so the next character is written to qstr[i+1], overwriting the '2'.
You will need to keep separate indexes for stepping through qry & qstr.

I agree with David.
It is advisable to do it in two-steps: in the first loop you just count the spaces:
int spaceCounter=0;
const int sourceLen = strlen(qry);
for(int i = 0; i < sourceLen; ++i)
if ( qry[i] == ' ')
++spaceCounter;
char* newString = (char*)malloc(sourceLen + 3*spaceCounter*sizeof(char) + 1)
//check for null!
for(int i = 0; i < sourceLen; ++i)
if ( qry[i] == ' ')
{
*newString++ = '%';
*newString++ = '2';
*newString++ = '0';
}
else
*newString++ = qry[i];
*newString = '\0';
Warning: code not tested.

You are assigning using the same counter I you will need to have 2 counters since the strings have different lengths
your else case assigns qstr[i] = qry[i]; after you have written the %20 you are at least off by 2 on the result string.

This is known as url encode. You can refer to this page to see some similar implementation: http://www.geekhideout.com/urlcode.shtml

char* toHexSpace(const char *s)
{
char *b=strcpy(malloc(3*strlen(s)+1),s),*p;
while( p=strchr(b,' ') )
{
memmove(p+3,p+1,strlen(p));
strncpy(p,"%20",3);
}
return b;
}
needs "free" in calling context.

Related

Trying to delete a specific character from a string in C?

I'm trying to delete a specific character (?) from the end of a string and return a pointer to a string, but it's not removing it at all at the moment. What am I doing wrong? Is there a better way to go about it?
char * word_copy = malloc(strlen(word)+1);
strcpy(word_copy, word);
int length = strlen(word_copy);
int i = 0;
int j = 0;
for (i = 0; word_copy[i] != '\0'; i++) {
if (word_copy[length - 1] == '?' && i == length - 1){
break;
}
}
for (int j = i; word_copy[j] != '\0'; j++) {
word_copy[j] = word_copy[j+1];
}
word = strdup(word_copy);
I'm immediately seeing a couple of problems.
The first for loop does nothing. It doesn't actually depend on i so it could be replaced with a single if statement.
if (word_copy[length - 1] == '?') {
i = length - 1;
} else {
i = length + 1;
}
The second for loop also acts as an if statement since it starts at the end of the string and can only ever run 0 or 1 times.
You could instead do something like this to remove the ?. This code will return a new malloced string with the last character removed if its ?.
char *remove_question_mark(char *word) {
unsigned int length = strlen(word);
if (length == 0) {
return calloc(1, 1);
}
if (word[length - 1] == '?') {
char *word_copy = malloc(length);
// Copy up to '?' and put null terminator
memcpy(word_copy, word, length - 1);
word_copy[length - 1] = 0;
return word_copy;
}
char *word_copy = malloc(length + 1);
memcpy(word_copy, word, length + 1);
return word_copy;
}
Or if you are feeling lazy, you could also just make the last character the new null terminator instead. Its essentially creates a memory leak of 1 byte, but that may be an acceptable loss. It should also be a fair bit faster since it doesn't need to allocate any new memory or copy the previous string.
unsigned int length = strlen(word);
if (length > 0 && word[length - 1] == '?') {
word[length] = 0;
}

what happens when i use malloc() twice in the same pointer?

I write a code to split string by delimiter.
I want the function get a string and return its strings divided.
It actually works except for one thing.
when I give string "test", it works.
but when I give string "1234 4567", I can access the value '4567', but not '1234'. (garbage value.)
also "1234 2345 3456 ..." results garbage value in only first argument '1234'.
I thought that using malloc() twice causes problem in the same pointer, but it doesn't.
What is the problem for my codes?
char **ft_set_char(char *str)
{
int i;
int j;
int k;
char *str_c;
char **ret;
k = 0;
j = 0;
ret = (char **)malloc(10);
str_c = (char *)malloc(5);
i = 0;
while (*(str + i) != '\0')
{
if (*(str + i) == ' ')
{
*(str_c + k) = '\0';
k = 0;
*(ret + j) = str_c;
j++;
i++;
str_c = (char *)malloc(5);
}
*(str_c + k) = *(str + i);
i++;
k++;
}
*(str_c + k) = '\0';
*(ret + j) = str_c;
*(ret + j + 1) = NULL;
return (ret);
}
ret = (char **)malloc(10);
That is not correct because it allocates 10 bytes and not 10 char * elements. It should be:
ret = malloc(10 * sizeof *ret);
Other unrelated issues but should be noted for best practice:
Don't cast the result of malloc
Don't use magic numbers like 10 and 5. For the former at least use a #define MAX_ARRAY_SIZE 10. For the latter, you can keep work out the exact size of the string to be copied from the original str - that will make your code more robust in case it is ever used with longer sub-strings.

Create a string from a vector of integers in C

I'm trying to create a string from a vector, something like this:
int vector[3] = {1, 2, 3}.
Then, the string I would get should be:
[1, 2, 3] stored in some char[] variable.
I tried to do it dynamically like follows:
void print_vector(int *vector, int lon){
char *str = (char*)calloc(3*lon, sizeof(char));
str[0] = "[";
str[1] = (char) vector[0];
for(int i = 1; i < lon; i += 3){
str[i] = (char)vector[i];
if(i != lon - 1){
str[i + 1] = (char)",";
str[i + 2] = " ";
}else{
str[i + 1] = "]";
}
}
printf("%s\n", str);
}
Where lon is the length of the vector, but I'm getting this warning from the compiler:
warning: the assignment to "char" from "char *" creates an integer from a pointer without a conversion [-Wint-conversion]
What am I doing wrong? Thanks.
There are several issues with your code -
You are using " instead of '. " is used to create a string literal which is of type char*. Hence the error you are getting.
(char) vector[0]; is not the right way to convert an integer to strings. You should use something like sprintf.
You haven't allocated enough memory with the call to calloc (the brackets, commas, space, nul-terminator).
You are only filling in certain characters in the buffer. The rest are initialized to 0. This will cause the string to terminate earlier than expected.
To start, you can fix your code as -
void print_vector(int *vector, int lon){
char *str = calloc(5*lon+3, sizeof(char));
// 5 for each character (3 characters per integer + space + comma.
// Two brackets and nul-terminator
strcpy(str, "[");
if (lon) {
sprintf(str+1, "%d", vector[0]);
for(int i = 1; i < lon; i++){
sprintf(str + strlen(str), ", %d", vector[i]);
}
}
strcat(str, "]");
printf("%s\n", str);
}
You can find the working demo here on ideone.
You're trying to assign strings to char array elements. You need to use single quotes to create char constants.
So
str[0] = "[";
should be
str[0] = '[';
and similarly for all the other assignments.
Another problem is that (char)vector[i] will not return the character representation of the number in vector[i]. It simply uses the integer as the character code. So if vector[i] is 1, this produces '\1', not '1'. The way to get the character representation of a number is with '0' + vector[i].
Finally, you need to add a null terminator to the end of the string so you can print it with %s formatting. And you should free it before returning to prevent a memory leak.
Other problems: You're only putting every 3rd element of vector into the string. You need to use separate indexes for vector and str. And array indexes start at 0, not 1.
void print_vector(int *vector, int lon){
char *str = (char*)calloc(3*lon, sizeof(char));
str[0] = "[";
str[1] = (char) vector[0];
for(int i = 0; i < lon; i++){
str[i*3] = '0' + vector[i];
if(i != lon - 1){
str[i*3 + 1] = ',';
str[i*3 + 2] = ' ';
}else{
str[i*3 + 1] = ']';
str[i*3 + 2] = '\0';
}
}
printf("%s\n", str);
}
Assuming every element in your vector is one digit, and every element is spaced identicially...
... and remembering you need to allicate a null byte at the end to terminate your string...
... perhaps something like this (uncompiled/untested):
void print_vector(int *vector, int lon){
char *str = (char*)calloc((3*lon)+1, sizeof(char));
char *s = str;
*s++ = "[";
int i=1;
while (i < lon) {
*s++ = vector[i] + 0x30; // ASCII "0"= 0x30, "1"= 0x31, ...
*s++ = ',';
*s++ = ' ';
i++;
}
s -= 2;
*s++ = ']';
*s++ = 0;
printf("%s\n", str);

How to append a character onto a string?

The examples I've seen on Stack Overflow come close to what my problem is but none of them seem to match, so I have to ask myself: How can I properly append a character to a string in C? I am aware that strcat() does not do the job, nor does using array values work properly. Here is my code:
char* buildWord(int posX, int posY, int nextX, int nextY, int gridX, int gridY, char** grid, char* str, int length){
int len2;
char* word = malloc(sizeof(char) * 20);
if(posX+nextX < 0 || posX+nextX > gridX)
return NULL;
if(posY+nextY < 0 || posY+nextY > gridX)
return NULL;
strcpy(word, str);
len2 = strlen(word);
word[len2 + 1] = grid[posX + nextX][posY + nextY]; //grid[x][y] represents a
word[len2 + 2] = '\0'; //single character
printf("%s", word);
length++;
if(length < 4)
word = buildWord(posX+nextX, posY+nextY, nextX, nextY, gridX, gridY, grid, word, length);
return word;
}
As you might guess, the purpose of this code is to build a string from a grid of letters with a particular direction in mind (similar to a wordsearch). For example, if my initial string "str" is "c" and am going in a diagonal direction where the next letter is "a", the string I want to put together is "ca".
When I run this code, the letter is not appended. The string remains the same throughout the code, which of course causes it to break. Is there a proper method to doing this?
You have a bug here:
word[len2 + 1] = grid[posX + nextX][posY + nextY]; //grid[x][y] represents a
word[len2 + 2] = '\0';
It should be:
word[len2] = grid[posX + nextX][posY + nextY]; //grid[x][y] represents a
word[len2 + 1] = '\0';
Remember that the index begin with 0

Managing memory when returning string in C

I have a CGI application I've been writing in Visual Studio Express 2013, but I've encountered a scenario where the program fails when the string passed into a function is more than 31 bytes. I would try to debug it myself, but everything works fine in Visual Studio Debugger, it's only in Command Prompt where I see the error.
I believe this to be the way that I've allocated(or not allocated) the memory. I have a function which takes in a string and returns the decoded string.
I've stripped everything down to just that function and main so you can see two cases, one which works in CMD and one which fails.
Here's the file:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Function: urlDecode
* Purpose: Decodes a web-encoded URL
* Input: const char* str - the URL to decode
* Output: char* - the decoded URL
*/
char *urlDecode(const char *str) {
int d = 0; /* whether or not the string is decoded */
char *dStr = malloc(strlen(str) + 1);
char *eStr = malloc(2); /* a hex code */
strcpy(dStr, str);
while (!d) {
d = 1;
int i; /* the counter for the string */
int j = strlen(dStr);
for (i = 0; i<j; ++i) {
if (dStr[i] == '%') {
if (dStr[i + 1] == 0)
return dStr;
if (isxdigit(dStr[i + 1]) && isxdigit(dStr[i + 2])) {
d = 0;
//combine the next two numbers into one
eStr[0] = dStr[i + 1];
eStr[1] = dStr[i + 2];
//convert it to decimal
long int x = strtol(eStr, NULL, 16);
//remove the hex
memmove(&dStr[i], &dStr[i + 2], strlen(dStr) - 1);
dStr[i] = x;
j = j - 2;
}
}
}
}
free(eStr);
return dStr;
}
int main(void)
{
//this one runs fine from command prompt
char *test1 = "s=W3%20%3A%20SVC&action=stop";
printf("%s\n", test1);
char *decoded1 = urlDecode(test1);
printf("%s\n", decoded1);
free(decoded1); //and I can even free the memory
//this one prints in command prompt, but the program crashes immediately after
char *test2 = "service=W3%20%3A%20SVC&action=stop";
printf("%s\n", test2);
char *decoded2 = urlDecode(test2);
printf("%s\n", decoded2);
//when I comment this free out, it debugs fine in VS, but still fails in cmd
//this is the reason I believe it's a memory error
//free(decoded2);
system("PAUSE"); //so I can see what's happening
return 0;
}
You failed to null-terminate eStr, and you did not allocate enough memory for it: you need three characters, not two.
Since eStr is so short, consider making it a stack variable, rather than allocating it on the dynamic store:
char eStr[] = "00";
This would allocate enough space, and make it unnecessary to free the pointer at the end of your function.
Another issue is memmove: it looks like your indexes are off. You could fix it, but it's much easier to avoid memmove altogether: rather than making substitutions in place, use str as your source, and dStr as your destination:
char *urlDecode(const char *str) {
int d = 0; /* whether or not the string is decoded */
char *dStr = malloc(strlen(str) + 1);
char *ret = dStr;
char eStr[] = "00";
strcpy(dStr, str);
while (!d) {
d = 1;
int i; /* the counter for the string */
int j = strlen(dStr);
for (i = 0; i<j; ++i) {
if (str[i] == '%') {
if (str[i + 1] == 0) {
break;
}
if (isxdigit(str[i + 1]) && isxdigit(str[i + 2])) {
d = 0;
//combine the next two numbers into one
eStr[0] = str[i + 1];
eStr[1] = str[i + 2];
//convert it to decimal
long int x = strtol(eStr, NULL, 16);
*dStr++ = x;
}
} else {
*dStr++ = str[i];
}
}
}
*dStr = 0;
return ret;
}
Demo.
should be
char *eStr = calloc(3,1); /* a hex code */
memmove(&dStr[i+1], &dStr[i + 3], strlen(&dStr[i+3])+1 );

Resources