i would like to download a webpage with wget in c.
i've wrote this code but when i try it, the program download the pages named with only a part of the given name and i found in the filename an invalid encoding.
the page name is like this
test0L���i}�X�����L�������R�td]�{��+`��U{�# (invalid encoding)
the important part of my program is this.
#define PAGE "http://deckbox.org/games/mtg/cards?p="
char *cat_url(char *s1, char *s2)
{
char *tmp;
tmp = (char*)malloc(sizeof(char*) * (strlen(s1) + strlen(s2)));
strcat(tmp, s1);
strcat(tmp, s2);
return tmp;
}
void get_card_name(char *pg_name)
{
int i;
int fk;
char *args[6], tmp;
for (i = 0; i < 8; i++) {
tmp = itoa(i);
args[0] = "wget";
args[1] = "-q";
args[2] = cat_url(PAGE, &tmp);
args[3] = "-O";
args[4] = cat_url("test", &tmp);
args[5] = NULL;
if (fork()) {
wait(&fk);
} else {
if (execvp(args[0], args) == -1) {
error_rep("ERROR.\n");
}
}
}
}
how can i fix the trouble?
Thanks
I think you need to use strcpy() for the s1 in cat_url(), like this
strcpy(tmp, s1);
...also the sizeof() is for a pointer and not the destination type char plus adding one char for the zero-termination. Maybe something like this
char *cat_url(char *s1, char *s2)
{
char *tmp;
tmp = (char*)malloc(sizeof(char)*(strlen(s1) + strlen(s2) + 1)); // sizeof char and not pointer
strcpy(tmp, s1); // strcpy here
strcat(tmp, s2);
return tmp;
}
Also Wizzard answer has an important point about itoa() and usage of its result.
...and as a last note, there is a memory leak as args[2] and argc[4] should be free()'d after they are used. You can also consider moving the whole args array into the else part of the of statement as it is not used in the if part.
The problem is with the following lines:
char tmp;
tmp = itoa(i);
Please try the following instead:
char tmp[2]; // to store 1 char and '\0'
...
snprintf (tmp, sizeof (tmp), "%d", i); // portable way to convert int to string
...
args[2] = cat_url(PAGE, tmp); // tmp is a pointer now
...
args[4] = cat_url("test", tmp);
Hope it helps !
Related
I have this code made for C++ (it works):
char* ConcatCharToCharArray(char *Str, char Chr)
{
char *StrResult = new char[strlen(Str) + 2];
strcpy(StrResult, Str);
StrResult[strlen(Str)] = Chr;
StrResult[strlen(Str) + 1] = '\0';
return StrResult;
}
/* Example: String = "Hello worl"
Char = "d"
Final string = "Hello world" */
The little problem is that I'm making a standard C program in Ubuntu and I need this code.
And "new" is NOT being recognized as a reserved word and there's even a red mark under it.
I tried: char *StrResult[strlen(Str) + 2], but it doesn't work because that way only admits constant values. I'm guessing "malloc" would be the standard C solution in here, how could I do this with "malloc" or any other way for that matter? Thank you so much.
new is the C++ way of allocating memory. In C you're right, you need to use malloc.
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t len = strlen( Str );
char *StrResult = malloc( len + 2 );
/* Check for StrResult==NULL here */
strcpy(StrResult, Str);
StrResult[len] = Chr;
StrResult[len+1] = '\0';
return StrResult;
}
When you're done with the memory, you'd call free( StrResult ).
Yes, you need malloc and you are confusing C with C++ here (since new comes from C++):
char *StrResult = (*char) malloc((strlen(Str) + 2) * sizeof(char));
char takes only one byte (see this question), so you don't need to multiply by it's size:
char *StrResult = (*char) malloc(strlen(Str) + 2);
One way:
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t StrLen = strlen(Str);
char *StrResult = malloc(StrLen + 2);
if(NULL == StrResult)
goto CLEANUP;
strcpy(StrResult, Str);
StrResult[StrLen++] = Chr;
StrResult[StrLen] = '\0';
CLEANUP:
return StrResult;
}
However, the above allocates a new string, instead of concatenating a character to an existing string. Here is a way to expand an existing string with an additional character:
int StrConcatChar(char **string, char character)
{
int rCode=0;
size_t stringLen;
char *temp;
if(NULL == string)
{
rCode=EINVAL;
goto CLEANUP;
}
stringLen = *string ? strlen(*string) : 0;
errno=0;
temp=realloc(*string, stringLen+2);
if(NULL == temp)
{
rCode=errno?errno:ENOMEM;
goto CLEANUP;
}
*string=temp;
(*string)[stringLen++] = character;
(*string)[stringLen] = '\0';
CLEANUP:
return(rCode);
}
The above function might be called like this:
{
int rCode=0;
char *buffer=NULL;
buffer=strdup("Hello worl");
if(NULL == buffer)
/* handle error condition */
rCode=StrConcatChar(&buffer, 'd');
if(rCode)
/* handle error condition */
...
if(buffer)
free(buffer);
}
char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source) +1;
char *dest = (char*)malloc(sizeof(char)*len);
while(*source != '\0')
{
// dest[ii++] = *source++;
*dest++ = *source++;
}
// dest[ii] = '\0';
*dest = '\0';
printf("\n copied string = %s", dest1);
return dest;
}
I want to copy source string to destination string.
The above api is returning null.
If I use array of character (this I have commented) then this api works to me.
Please help me to understand the difference between
dest[ii++] = *source++
and
*dest++ = *source++;
You're incrementing dest during the while loop. You need to keep hold of a pointer to the start of the buffer to return from the function.
char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source);
char *copy = malloc(len+1);
char* dest = copy;
while(*source != '\0')
{
*dest++ = *source++;
}
*dest = '\0';
printf("\n copied string = %s", copy);
return copy;
}
Note that you could save some code by using strcpy
char *stringcopywithpointer( const char *source)
{
int len = strlen(source);
char *copy = malloc(len+1);
strcpy(copy, source);
return copy;
}
and you could reduce this to a single line if you have access to the non-standard strdup
char *stringcopywithpointer( const char *source)
{
return strdup(source);
}
My opinion:
Avoid allocate memory in called function, better allot memory before calling a function
char *dest = ( char* ) malloc( sizeof( char ) * len ); // doesn't looks great
Irrespective of the machine, sizeof( char ) is always 1 byte. Less redundant is sizeof( char ) * len. Optimal would be malloc( sizeof( source ) ).
Pointers and arrays are related
You can either use
dest[i] = src[i];
*dst++ = *src++;
or
// assuming dst memory allocate by caller
while ( *dst++ = *src++);
1)
printf("\n copied string = %s", dest1);
should be
printf("\n copied string = %s", dest);
This could be a typo
2)
You can change:
while(*source != '\0')
{
*dest++ = *source++;
}
by
while(*dest++ = *source++);
3)
Concerning difference between dest[ii++] = *source++ and *dest++ = *source++;
There is no difference and should work if dest is defined in this way
char *dest = (char*)malloc(sizeof(char)*len);
If your array is define in this way:
char dest[len];
Then there is difference
You should not return an allocated string. This can easily lead to a memory leak.
Instead you should consider passing allocated memory into your function to copy it.
You can use your return value to return an error if anything went wrong.
This would change your signature to.
int stringcopywithpointer( char * dest, const char *source)
to make your code a little bit more versitile you could implement vargs and your signature would be:
int stringcopywithpointerf( char * dest, const * format, ... );
This is actually the already existing function sprintf.
int sprintf( char * dest, const * format, ... );
There are also secure variants of the function available and premade. You may want to consider using one of those.
If this is homework related take a look at this function:
char * myscpy(const char * SRC){
size_t size = strlen( SRC ) + 1 ;
char * START;
char * DST = ( char * ) malloc( size );
START = DST;
do
{
*DST = *SRC;
DST++;
SRC++;
}while( *SRC != 0 );
*DST = *SRC;
return START;
}
You likely want to add errorchecks to it like you had them in place (malloc etc.) in your original post.
"Please help me to understand the difference between dest[i++] and *dest++"
dest[i++] does not increment the pointer but the index to the pointer.
*dest++ increments the pointer after its original contendt was accessed.
Add char *dest1 = dest; right after malloc and then return dest1 and that will work.
Other possible change: replace while loop with post-condition loop (i.e. copy the zero byte first, then check if it was the end).
may be you need to add this line
char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source) +1;
char *ptr = NULL;
char *dest = (char*)malloc(sizeof(char)*len);
/** No Error Checking for malloc is a strict no no **/
if(dest == NULL)
return NULL;
/** hold the dest adress in ptr as we are incrementing dest **/
ptr = dest;
while(*source != '\0')
{
// dest[ii++] = *source++;
*dest++ = *source++;
}
// dest[ii] = '\0';
*dest = '\0';
//printf("\n copied string = %s", dest1); ??
printf("\n copied string = %s", ptr); // ptr will have our copied String
/** so return ptr not dest **/
return ptr;
}
how I do to repeat a string?
something like "hello world" * 3
the output "hello world hello world hello world"
In your source code, without much processing, probably the easiest way is with:
#define HI "hello world"
char str[] = HI " " HI " " HI;
This will declare a string of the requested value:
"hello world hello world hello world"
If you want code that will do it, you can use something like:
char *repeatStr (char *str, size_t count) {
if (count == 0) return NULL;
char *ret = malloc (strlen (str) * count + count);
if (ret == NULL) return NULL;
strcpy (ret, str);
while (--count > 0) {
strcat (ret, " ");
strcat (ret, str);
}
return ret;
}
Now keep in mind this can be made more efficient - multiple strcat operations are ripe for optimisation to avoid processing the data over and over (a). But this should be a good enough start.
You're also responsible for freeing the memory returned by this function.
(a) Such as with:
// Like strcat but returns location of the null terminator
// so that the next myStrCat is more efficient.
char *myStrCat (char *s, char *a) {
while (*s != '\0') s++;
while (*a != '\0') *s++ = *a++;
*s = '\0';
return s;
}
char *repeatStr (char *str, size_t count) {
if (count == 0) return NULL;
char *ret = malloc (strlen (str) * count + count);
if (ret == NULL) return NULL;
*ret = '\0';
char *tmp = myStrCat (ret, str);
while (--count > 0) {
tmp = myStrCat (tmp, " ");
tmp = myStrCat (tmp, str);
}
return ret;
}
You could use sprintf.
char s[20] = "Hello";
char s2[20];
sprintf(s2,"%s%s%s",s,s,s);
I've made this function based on earlier answers in this post.
I share it here because some of previous examples has been thrown me segfaults
const char* str_repeat(char* str, size_t times)
{
if (times < 1) return NULL;
char *ret = malloc(sizeof(str) * times + 1);
if (ret == NULL) return NULL;
strcpy(ret, &str);
while (--times > 0) {
strcat(ret, &str);
}
return ret;
}
http://ideone.com/5sNylW
#include <stdio.h>
#include <string.h>
int main(void) {
char k[100];
gets(k);
int lk=strlen(k);
int times;
scanf("%d",×);
int tl= times*lk;
int i,x=0;
for(i=lk-1;i<tl;i++)
{
k[i+1]=k[x];
x++;
}
for(i=0;i<tl;i++)
{
printf("%c",k[i]);
}
return 0;
}
You may try write own function. It will be work with single-length string also (i. e. duplication a single char). It use the function "strcat()" from the "string.h", so do not forget include this header.
char *
str_repeat(char str[], unsigned int times)
{
if (times < 1)
return NULL;
char *result;
size_t str_len = strlen(str);
result = malloc(sizeof(char) * str_len + 1);
while (times--) {
strcat(result, str);
}
return result;
}
But, if you need only duplication of a string for print it, try macro
#define PRINT_STR_REPEAT(str, times) \
{ \
for (int i = 0; i < times; ++i) \
printf("%s", str); \
puts(""); \
}
Results
PRINT_STR_REPEAT("-", 10); // ----------
puts(str_repeat("-", 10)); // ----------
PRINT_STR_REPEAT("$", 2); // $$
puts(str_repeat("$", 2)); // $$
PRINT_STR_REPEAT("*\t*", 10); // * ** ** ** ** ** ** ** ** ** *
puts(str_repeat("*\t*", 10)); // * ** ** ** ** ** ** ** ** ** *
PRINT_STR_REPEAT("*_*", 10); // *_**_**_**_**_**_**_**_**_**_*
puts(str_repeat("*_*", 10)); // *_**_**_**_**_**_**_**_**_**_*
Here's a way to repeat a string in C, N times.
That is have a string "abc"
and I want a string of length 7 that is comprised of this string repeated.
N = 7;
result: "abcabca"
while(Index != N){
repeatedString[Index] = oldString[Index%strlen(oldString)];
Index++;
}
Where repeated String would be "abcabca" at the end, and oldString is "abc".
gcc 4.4.4 c89
I am reading in from a text file and the text file consists of names in double quotes.
"Simpson, Homer"
etc
However, I want to remove the double quotes from the string.
This is how I have done it, but I am not sure its the best way.
int get_string(FILE *in, char *temp)
{
char *quote = NULL;
/* Get the first line */
fgets(temp, STRING_SIZE, in);
printf("temp before [ %s ]\n", temp);
/* Find the second quote */
if((quote = strrchr(temp, '"')) == NULL) {
fprintf(stderr, "Text file incorrectly formatted\n");
return FALSE;
}
/* Replace with a nul to get rid of the second quote */
*quote = '\0';
/* Move the pointer to point pass the first quote */
temp++;
printf("temp after [ %s ]\n", temp);
return TRUE;
}
Many thanks for any suggestions,
No, this won't work. You are changing the parameter temp, but the calling function will still have an old value. The temp outside the function will point to the opening quote. You ought to move the characters in your buffer.
However I would suggest allocating the buffer in heap and returning a pointer to it, letting the caller free the buffer when needed. This seems to be a cleaner solution. Again, this way you won't rely on the caller to pass a sufficiently large buffer.
In general, a robust reading lines from a text file is not a trivial task in C, with its lack of automatic memory allocating functions. If possible to switch to C++, I would suggest trying much simpler C++ getline.
char *foo(char *str, int notme)
{
char *tmp=strdup(str);
char *p, *q;
for(p=str, q=tmp; *p; p++)
{
if((int)*p == notme) continue;
*q=*p;
q++;
}
strcpy(str, tmp);
free(tmp);
return str;
}
simple generic remove a char
is all lines look that way why not simple remove the first and the last char?
quote++; // move over second char
quote[strlen(quote)-1]='\0'; // remove last char
Don't know if this will help, it is a simple tokenizer i use
#include <stdlib.h>
#include <string.h>
int token(char* start, char* delim, char** tok, char** nextpos, char* sdelim, char* edelim) {
// Find beginning:
int len = 0;
char *scanner;
int dictionary[8];
int ptr;
for(ptr = 0; ptr < 8; ptr++) {
dictionary[ptr] = 0;
}
for(; *delim; delim++) {
dictionary[*delim / 32] |= 1 << *delim % 32;
}
if(sdelim) {
*sdelim = 0;
}
for(; *start; start++) {
if(!(dictionary[*start / 32] & 1 << *start % 32)) {
break;
}
if(sdelim) {
*sdelim = *start;
}
}
if(*start == 0) {
if(nextpos != NULL) {
*nextpos = start;
}
*tok = NULL;
return 0;
}
for(scanner = start; *scanner; scanner++) {
if(dictionary[*scanner / 32] & 1 << *scanner % 32) {
break;
}
len++;
}
if(edelim) {
*edelim = *scanner;
}
if(nextpos != NULL) {
*nextpos = scanner;
}
*tok = (char*)malloc(sizeof(char) * (len + 1));
if(*tok == NULL) {
return 0;
}
memcpy(*tok, start, len);
*(*tok + len) = 0;
return len + 1;
}
The parameters are:
char* start, (pointer to the string)
char* delim, (pointer to the delimiters used to break up the string)
char** tok, a reference (using &) to a char* variable that will hold the toke
char** nextpos, a reference (using &) to a char* variable that will hold the position after the last token.
char* sdelim, a reference (using &) to a char variable that will hold the value of the -start delimiter
char* edelim, a reference (using &) to a char varaible that will hold the value of the end delimiter
The last three are optional.
Pass in the start address, the delimeter is a ", and pass reference to a char * to hold the actual middle string.
The result is a newly allocated string so you have to free it.
int get_string(FILE *in, char *temp)
{
char *token = NULL;
/* Get the first line */
fgets(temp, STRING_SIZE, in);
printf("temp before [ %s ]\n", temp);
/* Find the second quote */
int length = token(temp, "\"", &token, NULL, NULL, NULL)
// DO STUFF WITH THE TOKEN
printf("temp after [ %s ]\n", token);
// DO STUFF WITH THE TOKEN
// FREE IT!!!
free(token);
return TRUE;
}
The tokenizer is a multipurpose tool that can be used in a crap ton of places, this being a very small example.
Suppose
string="\"Simpson, Homer\""
then
string_without_quotes=string+1;
string_without_quotes[strlen(string)-2]='\0';
ready!
I'm going to try to explain the problem.
I am getting a string containing a registry key. For example:
HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey
now, I need to parse that string into 3 different char (or char *) variables. After the parsing it'll be something like:
string1 = HKEY_CURRENT_USER
string2 = \Software\MyProgram\SomeOtherValue\ /* with the '\' */
string3 = SomeKey
Not only do I need to group the backslashes; I also don't know how many of them are there. I could have something like:
HKEY_CURRENT_USER\Software\SomeKey
or something like:
HKEY_CURRENT_USER\Software\SomeValue\SomeOthervalue\Someblah\SomeKey
I tried with strtok() and strcspn() but i'm getting very confused here...
Any idea how to get this done?
Code is appreciated.
Thanks!
Pseudo-Code:
Step 1: Scan forward until the first "\", note the index.
Step 2: Scan Backward from the end to the last "\"
(the first "\" encountered when going backwards), note the index.
Step 3: StrCpy the relevant pieces out into 3 strings.
Code: (does not rely on strrchr, or other methods you seem to have issues with)
void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key);
int main(void)
{
char* regKey = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
char* TopLevel;
char* Path;
char* Key;
ParseRegEntry(regKey, &TopLevel, &Path, &Key);
printf("1: %s\n2: %s\n3: %s\n", TopLevel, Path, Key);
free(TopLevel);
free(Path);
free(Key);
return 0;
}
void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key)
{
int firstDelimiter = 0;
int lastDelimiter = strlen(regKey)-1;
int keyLen;
while(regKey[firstDelimiter] != '\\')
{
firstDelimiter++;
}
while(regKey[lastDelimiter] != '\\')
{
lastDelimiter--;
}
keyLen = strlen(regKey) - lastDelimiter-1;
*TopLevel = (char*)malloc(firstDelimiter+1);
strncpy(*TopLevel, regKey, firstDelimiter);
(*TopLevel)[firstDelimiter] = '\0';
*Path = (char*)malloc(lastDelimiter - firstDelimiter+2);
strncpy(*Path, regKey+firstDelimiter, lastDelimiter - firstDelimiter);
(*Path)[lastDelimiter-firstDelimiter] = '\0';
*Key = (char*)malloc(keyLen+1);
strncpy(*Key, regKey+lastDelimiter+1, keyLen);
(*Key)[keyLen] = '\0';
}
strchr(char*, char) : locate first occurrence of char in string
strrchr(char*, char) : locate last occurrence of char in string
char* str = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char token1[SIZE], token2[SIZE], token3[SIZE];
char* first = strchr(str, '\\');
char* last = strrchr(str, '\\')+1;
strncpy(token1, str, first-str);
token1[first-str] = '\0';
strncpy(token2, first, last-first);
token2[last-first] = '\0';
strcpy(token3, last);
We use strchr to find the first '\', and strrchr to find the last '\'. We then copy to token1, token2, token3 based on those positions.
I decided to just use fixed size buffers instead of calloc-ing, because that's not so important to illustrate the point. And I kept messing it up. :)
Copy the string into an allocated one and split the variable placing a '\0' in the slash where you want to truncate it.
You can "scan" the string for slashes using the strchr function.
void to_split(char *original, int first_slash, int second_slash, char **first, char **second, char **third) {
int i;
char *first_null;
char *second_null;
char *allocated;
if (first_slash >= second_slash)
return;
allocated = malloc(strlen(original) + 1);
*first = allocated;
strcpy(allocated, original);
for (i = 0, first_null = allocated; i < first_slash && (first_null = strchr(first_null,'\\')); i++);
if (first_null) {
*first_null = '\0';
*second = first_null + 1;
}
second_null = allocated + strlen(original);
i = 0;
while (i < second_slash && second_null > allocated)
i += *second_null-- == '\\';
if (++second_null > allocated) {
*second_null = '\0';
*third = second_null + 1;
}
}
Usage:
int main (int argc, char **argv) {
char *toSplit = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
char *first;
char *second;
char *third;
to_split(toSplit, 1, 3, &first, &second, &third);
printf("%s %s %s\n", first, second, third);
return 0;
}
It isn't the best code in the world, but it gives you an idea.
Here's an example using strchr and strrchr to scan forwards and backwards in the string for the '\'.
char str[] = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char *p, *start;
char root[128], path[128], key[128];
p = strchr (str, '\\');
strncpy (root, str, p - str);
start = p;
p = strrchr (str, '\\') + 1;
strncpy (path, start, p - start);
strcpy (key, p);