I want to use pointer - c

I have pointer like this => char* str={"you","we","they"};
I want to take 'we' or "they" .how is it posible ?
can you sy something about pointer ?

It seems that you mean something like the following
char *str[] = { "you", "we", "they" };
for ( size_t i = 0; i < sizeof( str ) / sizeof( *str ); i++ )
{
puts( str[i] );
}
Or
char *str[] = { "you", "we", "they" };
for ( size_t i = 0; i < sizeof( str ) / sizeof( *str ); i++ )
{
for ( char *p = str[i]; *p != '\0'; ++p ) putc( *p );
printf( "\n" );
}

Related

Is there any way to split a CONST char * with a delimiter into an array?

I'm trying to split a given string (input) into an array of elements. Here is my code:
char *buff = save_to_buff(); // save the input
int token_count = 1;
for(int i = 0; buff[i] != '\0';i++)
{
if(buff[i] == ' ')
{
token_count++;
}
}
char *token = strtok(buff, " ");
char *arr[token_count];
for(int i = 0;token != NULL;i++)
{
arr[i] = token;
token = strtok(NULL, " ");
}
for(int i = 0; i < token_count;i++)
{
printf("%s ", arr[i]);
}
It works, however I need to make a function char **parse_cmdline(const char *cmdline) which splits the buff(cmdline) in this case into an array, but how can I do that if it is even possible? I either get a warning that the 'const' qualifier is discared or an error. Is there any way?
You can split the function into two functions.
The first one will return the number of tokens in a given string. Using the return value of the function you can allocate an array of pointers the number of elements of which is equal to the number of tokens in the given string plus one. That is the array of tokens will end with a null pointer.
The second function will fill the provided array with tokens of the given string.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
size_t count_tokens( const char *s1, const char *s2 )
{
size_t n = 0;
while (*s1)
{
s1 += strspn( s1, s2 );
if (*s1)
{
++n;
s1 += strcspn( s1, s2 );
}
}
return n;
}
size_t get_tokens( char **s1, const char *s2, const char *s3 )
{
size_t n = 0;
while (*s2)
{
s2 += strspn( s2, s3 );
if (*s2)
{
++n;
const char *p = s2;
s2 += strcspn( s2, s3 );
size_t len = s2 - p;
*s1 = malloc( len + 1 );
if (*s1)
{
memcpy( *s1, p, len );
( *s1 )[len] = '\0';
}
++s1;
}
}
*s1 = NULL;
return n;
}
int main( void )
{
const char *s1 = "Hello World!";
size_t n = count_tokens( s1, " " );
printf( "%zu\n", n );
char **p = malloc( ( n + 1 ) * sizeof( char * ) );
get_tokens( p, s1, " " );
for ( size_t i = 0; i < n; i++ )
{
if ( p[i] ) puts( p[i] );
}
for (size_t i = 0; i < n; i++)
{
free( p[i] );
}
free( p );
}
The program output is
2
Hello
World!
As a delimiter of tokens you can pass any string to the functions as for example " \t\n'.
const objects cannot be modified. It is undefined behaviour. You need to make a modifiable copy of the string before you use strtok.
char **split(const char *restrict str, const char *restrict delim)
{
char **result = NULL;
char *copy;
size_t ntokensLen;
if(str && delim && *str && *delim)
{
copy = malloc(ntokensLen = strlen(str + 1));
if(copy)
{
char *token;
memcpy(copy, str, ntokensLen + 1);
ntokensLen = 0;
token = strtok(copy, delim);
if(!token) free(copy);
while(token)
{
char **tmp;
tmp = realloc(result, (ntokensLen + 2) * sizeof(*tmp));
if(!tmp) { /* error hanling */}
result = tmp;
result[ntokensLen] = token;
result[ntokensLen + 1] = NULL;
token = strtok(NULL, delim);
ntokensLen++;
}
}
}
return result;
}
int main(void)
{
const char *str = "This!is string ^to test...";
char **result = split(str, "! ^.");
size_t cnt = 0;
while(result[cnt])
{
printf("result[%zu] = `%s`\n", cnt, result[cnt]);
cnt++;
}
// how to free?
free(result[0]);
free(result);
}
EDIT:
Added How to free. result holds the reference to realloced memory, result[0] to malloced.
result is NULL pointer terminated.
Other split versions:
char **mystrtok(const char *str, const char *del, int alowempty)
{
char **result = NULL;
const char *end = str;
size_t size = 0;
int extrachar;
while(*end)
{
if((extrachar = !!strchr(del, *end)) || !*(end + 1))
{
/* add temp variable and malloc / realloc checks */
/* free allocated memory on error */
if(!(!alowempty && !(end - str)))
{
extrachar = !extrachar * !*(end + 1);
result = realloc(result, (++size + 1) * sizeof(*result));
result[size] = NULL;
result[size -1] = malloc(end - str + 1 + extrachar);
strncpy(result[size -1], str, end - str + extrachar);
result[size -1][end - str + extrachar] = 0;
}
str = end + 1;
}
end++;
}
return result;
}
double pointer supplied by the caller
char **split(char **argv, int *argc, const char *str, const char *delimiter, int allowempty)
{
char *string = malloc(strlen(str + 1));
strcpy(string, str);
*argc = 0;
do
{
if(*string && (!strchr(delimiter, *string) || allowempty))
{
argv[(*argc)++] = string;
}
while(*string && !strchr(delimiter, *string)) string++;
if(*string) *string++ = 0;
if(!allowempty)
while(*string && strchr(delimiter, *string)) string++;
}while(*string);
return argv;
}

removing duplicated names for array in c

this is what i have to make: c. It should be possible to remove an animal with a specified name. If more animals with the same name exist, it should remove all the animal with the same name.
this is my code:
void deleteAnimalByName(char *animalName, int *nrOfAnimals, ANIMAL *animalArray)
{
for(int i = 0; i < *nrOfAnimals; i ++)
{
if(strcmp((animalArray + i)->Name, animalName) == 0)
{
for(int j = i; j < *nrOfAnimals - 1; j++)
{
animalArray[j] = animalArray[j + 1];
}
(*nrOfAnimals)--;
}
}
}
the outcome after tyring to delete the animals with the same name:
Animals in shelter: 1
Name: ted
Species: Parrot
Age: 1
only one gets deleted, the other one stays. what could cause this?
For starters the function should be declared at least like
size_t deleteAnimalByName( ANIMAL *animalArray, size_t nrOfAnimals, const char *animalName );
And the function can be defined like
size_t deleteAnimalByName( ANIMAL *animalArray, size_t nrOfAnimals, const char *animalName )
{
size_t n = 0;
for ( size_t i = 0; i < nrOfAnimals; i++ )
{
if ( strcmp( animalArray[i].Name, animalName ) != 0 )
{
if ( n != i ) animalArray[n] = animalArray[i];
++n;
}
}
return n;
}
As for your approach then it at least is inefficient because you move all elements of the array one position left after finding an element that need to be deleted.
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
typedef struct ANIMAL
{
char *Name;
} ANIMAL;
size_t deleteAnimalByName( ANIMAL *animalArray, size_t nrOfAnimals, const char *animalName )
{
size_t n = 0;
for ( size_t i = 0; i < nrOfAnimals; i++ )
{
if ( strcmp( animalArray[i].Name, animalName ) != 0 )
{
if ( n != i ) animalArray[n] = animalArray[i];
++n;
}
}
return n;
}
int main(void)
{
ANIMAL animalArray[] =
{
{ "hare" }, { "hare" }, { "fox" }, { "hare" }
};
size_t nrOfAnimals = sizeof( animalArray ) / sizeof( *animalArray );
nrOfAnimals = deleteAnimalByName( animalArray, nrOfAnimals, "hare" );
for ( size_t i = 0; i < nrOfAnimals; i++ )
{
printf( "%s ", animalArray[i].Name );
}
putchar( '\n' );
return 0;
}
The program output is
fox

Creating 2 (or 3?) dimensional array of string in C

I want to create an array of string like:
{{"zero","zero"},
{"zero","one"},
{"one","zero"},
{"one","one"}}
If I am not wrong I need 3D array. How can I create it with using dynamic memory allocation and how to return it from function? I mean how is my function should be (char ***getString etc...) and in my main function, how can I use it? Is char ***string = getstring(); work?
I didn't get I have to use 3d array yet, I tried it with 2 mallocs.
I create string of array in function like
char** editKeys = malloc(128 * sizeof(char*));
for (int i = 0; i < 128; i++ )
{
editKeys[i] = (char*) calloc(2, sizeof(char));
}
and it works in function. After that I calledmy function from main like
char **editFile=getEditFile();
printf("%s",editFile[0][0]);
at this point I failed and now I can't be sure is it 2d or 3d and my brain is failed me too. Can't think how can I turned it in 3d array.
If your compiler supports variable length arrays then you can allocate the array the following way
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f( size_t n1, size_t n2, size_t n3, char s[n1][n2][n3] )
{
for ( size_t i = 0; i < n1; i++ )
{
if ( i < n1 / 2 )
{
strcpy( s[i][0], "zero" );
}
else
{
strcpy( s[i][0], "one" );
}
if ( i % 2 == 0 )
{
strcpy( s[i][1], "zero" );
}
else
{
strcpy( s[i][1], "one" );
}
}
}
int main(void)
{
enum { N1 = 4, N2 = 2, N3 = 5 };
char ( *p )[N2][N3] = malloc( sizeof( char[N1][N2][N3] ) );
f( N1, N2, N3, p );
for ( size_t i = 0; i < N1; i++ )
{
printf( "\"%s\" \"%s\"\n", p[i][0], p[i][1] );
}
free( p );
return 0;
}
The program output is
"zero" "zero"
"zero" "one"
"one" "zero"
"one" "one"
Or you can indeed allocate an array of arrays of arrays.
For example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f( char ***s, size_t n1, size_t n2, size_t n3 )
{
for ( size_t i = 0; i < n1; i++ )
{
if ( i < n1 / 2 )
{
strcpy( s[i][0], "zero" );
}
else
{
strcpy( s[i][0], "one" );
}
if ( i % 2 == 0 )
{
strcpy( s[i][1], "zero" );
}
else
{
strcpy( s[i][1], "one" );
}
}
}
int main(void)
{
enum { N1 = 4, N2 = 2, N3 = 5 };
char ***p = malloc( N1 * sizeof( char ** ) );
for ( size_t i = 0; i < N1; i++ )
{
p[i] = malloc( N2 * sizeof( char * ) );
for ( size_t j = 0; j < N2; j++ )
{
p[i][j] = malloc( N3 );
}
}
f( p, N1, N2, N3 );
for ( size_t i = 0; i < N1; i++ )
{
printf( "\"%s\" \"%s\"\n", p[i][0], p[i][1] );
}
for ( size_t i = 0; i < N1; i++ )
{
for ( size_t j = 0; j < N2; j++ )
{
free( p[i][j] );
}
free( p[i] );
}
free( p );
return 0;
}
Atain the program output is
"zero" "zero"
"zero" "one"
"one" "zero"
"one" "one"
There is also a third approach where the number of pointers can be less than in the last case. All you need is to allocate a one dimensional array of pointers to first elements of two dimensional arrays.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { N1 = 4, N2 = 2, N3 = 5 };
void f( char ( **s )[N3], size_t n1 )
{
for ( size_t i = 0; i < n1; i++ )
{
if ( i < n1 / 2 )
{
strcpy( s[i][0], "zero" );
}
else
{
strcpy( s[i][0], "one" );
}
if ( i % 2 == 0 )
{
strcpy( s[i][1], "zero" );
}
else
{
strcpy( s[i][1], "one" );
}
}
}
int main(void)
{
char ( **p )[N3] = malloc( N1 * sizeof( char ( * )[N3] ) );
for ( size_t i = 0; i < N1; i++ )
{
p[i] = malloc( N2 * sizeof( char[N3] ) );
}
f( p, N1 );
for ( size_t i = 0; i < N1; i++ )
{
printf( "\"%s\" \"%s\"\n", p[i][0], p[i][1] );
}
for ( size_t i = 0; i < N1; i++ )
{
free( p[i] );
}
free( p );
return 0;
}
And at last (I hope) there is a forth approach to declare at first an array of pointers to arrays.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { N1 = 4, N2 = 2, N3 = 5 };
void f( char * ( *s )[N2], size_t n1, size_t n3 )
{
for ( size_t i = 0; i < n1; i++ )
{
if ( i < n1 / 2 )
{
strcpy( s[i][0], "zero" );
}
else
{
strcpy( s[i][0], "one" );
}
if ( i % 2 == 0 )
{
strcpy( s[i][1], "zero" );
}
else
{
strcpy( s[i][1], "one" );
}
}
}
int main(void)
{
char * ( *p )[N2] = malloc( N1 * sizeof( char * [N2] ) );
for ( size_t i = 0; i < N1; i++ )
{
for ( size_t j = 0; j < N2; j++ )
{
p[i][j] = malloc( N3 * sizeof( char ) );
}
}
f( p, N1, N3 );
for ( size_t i = 0; i < N1; i++ )
{
printf( "\"%s\" \"%s\"\n", p[i][0], p[i][1] );
}
for ( size_t i = 0; i < N1; i++ )
{
for ( size_t j = 0; j < N2; j++ ) free( p[i][j] );
}
free( p );
return 0;
}
If the compiler indeed supports variable length array then the first approach is the best.
Note: In the approaches sometimes some parameter as for example n2 is not used because I knwo that it is equal to 2. But in general it should be specified.

C - Appending to string - Possible memory errors

I am trying to a create a function that keeps on appending a string to a char variable. However, some times it works and other times it doesn't. I am wondering where the bug is?
char *final_output = NULL;
void add_string(const char *);
int main(void) {
add_string("Hello world\n");
add_string("This is my new function!\n");
/* Let's print */
while (final_output && *final_output) {
printf("%c", *final_output);
*final_output++;
}
}
void add_string(const char *text) {
if (final_output == NULL) {
final_output = malloc(strlen(text) + 1);
}
else {
final_output = (char *) realloc(final_output, strlen(final_output) + strlen(text) + 2);
}
strncat(final_output, text, strlen(text));
}
The problem is in function add_string. You do not append the allocated or copied array with the terminating zero after statements
final_output = malloc(strlen(text) + 1);
and
strncat(final_output, text, strlen(text));
Rewrite the function the following way
void add_string( const char *s )
{
if ( final_output == NULL )
{
final_output = malloc( strlen( s ) + 1 );
final_output[0] = '\0';
}
else
{
final_output = realloc( final_output, strlen( final_output ) + strlen( s ) + 1 );
}
strcat( final_output, s );
}

How to sort a struct using qsort?

I have a struct declared like this
struct data
{
char * Date;
char * String;
};
struct data **RegArray = NULL;
int ArrayCount = 0;
I add new items to the array this way:
struct data **tmp = ( struct data ** )realloc( RegArray, ( ArrayCount + 1 ) * sizeof( struct data * ) );
if ( tmp == NULL )
{
printf( "\nRealloc failed!" );
return;
}
RegArray = tmp;
RegArray[ ArrayCount ] = ( struct data * )malloc( sizeof **RegArray );
if ( RegArray[ ArrayCount ] == NULL )
{
printf( "\nMalloc failed!" );
return;
}
RegArray[ ArrayCount ]->Date = _strdup( cDate );
RegArray[ ArrayCount ]->String = _strdup( cString );
ArrayCount++;
The function which compares the values:
int CompareByDate( const void *elem1, const void *elem2 )
{
//return ( ( data* )elem1 )->Date > ( ( data* )elem2 )->Date ? 1 : -1;
return strcmp( ( ( data* )elem1 )->Date, ( ( data* )elem2 )->Date );
}//CompareByDate
And finally I call qsort like this:
qsort( RegArray, ArrayCount-1, sizeof( data ), CompareByDate );
The problem is, that the data won't be sorted.
So what am I doing wrong?
Thanks!
In your qsort call and comparison function, you forget that you're dealing with an "array" of pointers. The easiest change is to not use an array of pointers:
struct data *RegArray = NULL;
/* ... */
struct data *tmp = realloc( RegArray, ( ArrayCount + 1 ) * sizeof( struct data ) );
if ( tmp == NULL )
{
printf( "\nRealloc failed!" );
return;
}
RegArray = tmp;
RegArray[ ArrayCount ].Date = _strdup( cDate );
RegArray[ ArrayCount ].String = _strdup( cString );
ArrayCount++;
This will make your qsort call (and comparison function) work as they are shown in the question.
If you don't want to change the code as outlined above, you have to change the qsort call and comparison function:
qsort( RegArray, ArrayCount-1, sizeof( data * ), CompareByDate );
/* ... */
int CompareByDate( const void *elem1, const void *elem2 )
{
struct data **d1 = (struct data **) elem1;
struct data **d2 = (struct data **) elem2;
return strcmp((*d1)->Date, (*d2)->Date);
}

Resources