copying array of string pointers to a new array in C - c

we get input from user (command line) and store it in in char* input[].
This input will look like this, when the user inputs all required information:
input[]: add John Smith (male) <relation> Emma Stone (female).
Then we want to copy it to new_input[] with 8 positions (for example John would be on the position 1). In our first example this will look like the same:
new_input []: add John Smith (male) <relation> Emma Stone (female)
But there are possibilities that we don't get all the information from the user. Especially it is most likely we don't get the last name. So, during the copy we need to add some ‘if-statements’ to check if the user puts e.g. Smith or not. If not – we want write ‘NULL’ at the positions 2 and 6. The array looks then like:
if input []: add John (male) <relation> Emma (female)
new_input []: add John NULL (male) <relation> Emma NULL (female)
Unfortunately, we have difficulties with copying array of string pointers to a new array.
We tried memcpy(), new_input[i] = input[i] (in a for-loop).
EDIT: here is code and i also edit example above, (new_input with NULL on position 2 and 6 if last names are missing)
`int main(int argc, char* argv[])
{
char* copy_input = NULL;
int len_max = 256;
int error = 1;
char* input = (char*) malloc(len_max* sizeof(char));
if (argc == 1)
{
while(1)
{
printf("cmd> ");
char read[len_max];
input = fgets(read, len_max, stdin);
int len = strlen(read);`
if(read[len-1] == '\n')
{
read[len-1] = '\0';
}
copy_input = input;``
error = handleUserInput (copy_input);
}`
in handle user command, we split string by space and check first string, if it is " add " , go to function addCommand (in)
`
int handleUserInput(char* input) // takes char input from main and compares type of command
{
printf("input: %s\n",input );
char* in[8];
int i = 0;
char* temp;
char delimiter[] = " ";
temp = strtok(input, delimiter);
in[i++] = temp;
while( temp != NULL)
{
temp = strtok(NULL, delimiter);
in[i++] = temp;
// printf("%s\n", temp);
}
if(!strcmp(in[0], "add"))
{
addCommand(in);
}`
In function add command, we want to do copy input to new_input as i described above...
`int addCommand(char* input[]) //
{
char* new_input[];
`

If you are using the new_input[i] = input[i]
You're gonna assign the pointeur of input[i] to the new_input[i]
then thing is that it would not be a copy it's just a copy of the string personnal adress.
So if u want to make a real copy with it's "own memory" u need to first allocate a new string and then copy the content of the last string in the new.
(man strdup)
To copy an array of string pointer you will probably do a basic method wich mean to first allocate your double pointeur (char **array)
to receive your new content.
and then loop to copy all the content with the method that i've show you just before

Related

SOLVED-what am I doing wrong that strtok does right in splitting a string

Previous question was : what am I doing wrong that strtok does right in splitting a string. Also separating the strtok to a function suddenly doesn't produce correct result?
This is the first time that I ask a question in stackoverflow so forgive me if this is wordy and incoherent. The last part of the question is elaborated at the bottom part of this question body.
So, I was doing a course assessment assigned by my college, in that, one question is :
Remove duplicate words and print only unique words
Input : A single sentence in which each word separated by a space
Output : Unique words separated by a space [Order of words should be same as in input]
Example:
Input : adc aftrr adc art
Output : adc aftrr art
Now, I have the solution which is to split the string on whitespaces and adding the word to a array(set) if it is not already exists, but it is the implementation part that makes me to plug my hair out
#include <stdio.h>
#include <string.h>
#define MAX 20
int exists(char words[][MAX], int n, char *word){ // The existence check function
for(int i=0;i < n;i++)
if(strcmp(words[i],word) == 0)
return 1;
return 0;
}
void removeDuplicateOld(char*);
void removeDuplicateNew(char*);
int main(){
char sentence[MAX*50] = {0}; //arbitary length
fgets(sentence,MAX*50,stdin);
sentence[strcspn(sentence,"\n")]=0;
printf("The Old One : \n");
removeDuplicateOld(sentence);
printf("\nThe New One : \n");
removeDuplicateNew(sentence);
}
The fucntion that uses strtok to split string :
void removeDuplicateNew(char *sentence){
char words[10][MAX] = {0};
int wi=0;
char *token = strtok(sentence," ");
while(token != NULL){
if(exists(words,wi,token)==0) {
strcpy(words[wi++],token);
}
token = strtok(NULL," ");
}
for(int i=0;i<wi;i++) printf("%s ",words[i]);
}
The old function that uses my old method (which is constructing a word until I hit whitespace) :
void removeDuplicateOld(char *sentence){
char objects[10][MAX] = {0}; //10 words with MAX letters
char tword[MAX];
int oi=0, si=0, ti=0;
while(sentence[si]!='\0'){
if(sentence[si] != ' ' && sentence[si+1] != '\0')
tword[ti++] = sentence[si];
else{
if(sentence[si+1] == '\0')
tword[ti++]=sentence[si];
tword[ti]='\0';
if(exists(objects,oi,tword) == 0){
strcpy(objects[oi++],tword);
}
ti=0; // The buffer[tword] is made to be overwritten
}
si++;
}
for(int i=0;i<oi;i++)
printf("%s ",objects[i]);
}
Solved : changed if(sentence[si+1] == '\0') to if(sentence[si+1] == '\0' && sentence[si]!=' ')
Here is the output :
input : abc def ghi abc jkl ghi
The Old One :
abc def ghi jkl
The New One :
abc def ghi jkl
Note trailing whitespaces in input and output is not checked as their own driver code doesn't properly handle them while strtok method does and it passes all tests.
Now both methods seems to be producing same results but they are indeed producing different outputs according to test cases and in top of that separating strtok method as a separate function[removeDuplicateNew] fails one test case while writing it in main method itself passes all test, see these results :
Old Method Test Case results
Strtok Method as Separate Function Test Case Results
Following Was Moved To A separate Question Thread
When Coded in main method itself :
int main(){
char sentence[MAX*50] = {0}; //arbitary length
fgets(sentence,MAX*50,stdin);
sentence[strcspn(sentence,"\n")] = 0;
char words[10][MAX] = {0};
int wi=0;
char *token = strtok(sentence," ");
while(token != NULL){
if(exists(words,wi,token)==0) {
strcpy(words[wi++],token);
}
token = strtok(NULL," ");
}
for(int i=0;i<wi;i++) printf("%s ",words[i]);
}
Strtok Method as inline code Test Case Results
For the record, it is the same code just placed in main method, so what the heck happens here that when I separate it as a function and pass the string as argument it suddenly isn't working properly.
Also any advice on my question building, wording is appreciated.
Your code...
void removeDuplicateOld(char *sentence){
char objects[10][MAX] = {0}; //10 words with MAX letters
char tword[MAX];
int oi=0, si=0, ti=0;
while(sentence[si]!='\0'){
if(sentence[si] != ' ' && sentence[si+1] != '\0')
tword[ti++] = sentence[si];
else{
// right here have hit SP.
// if SP followed by '\0'
// then append SP to my word... wrong! <=====
if(sentence[si+1] == '\0')
tword[ti++]=sentence[si];
tword[ti]='\0';
This is why the library function strtok() works better than hand rolled code.It has been tested and proven to work as it says it does.
There's a better way to use strtok()
for( char *p = sentence; (p = strtok( p, " \n") ) != NULL; p = NULL )
if( exists( words, wi, p ) == 0 )
strcpy( words[wi++], p );
That's all you need. strtok() will even trim the LF off the buffer for you, no extra charge.
Final suggestion: Instead of a fixed-sized array of pointers to words, you might consider a linked-list (LL) that can easily grow. The function that would append a new word to the end of the list can quietly eat the word if it turns out to be a duplicate found while traversing to append to the end of the LL.

Splitting a string into two and assigning to two char array

I have a string like:
my age is 22\r\n\r\n and I live in Rostock
and some other strings like:
I like to swim\r\n\r\n .Yesterday I competed with my 2 friends
Now I want to split a string by \r\n\r\n and have it associated with buffer. Here is what I am trying to do:
char buffer[500];
strcpy(buffer, "my age is 22\r\n\r\n and I live in Rostock");
char *p = buffer;
if((p = strchr(p,"\r\n\r\n"))) {
p[strcspn(p,"tock")] = 0; // trying to slice until the end
}
printf("%s", p);
This gives me a warning as I try to compile saying warning: passing argument 2 of ‘strchr’ makes integer from pointer without a cast I could not understand what this meant.
Also what is good way to split this into 2 char buffers?
strchr expects a mere char and not a string for its second parameter. So you can only pass it a single character.
In C a char is a single character and strings are null terminated char arrays.
What you want to do is probably:
char buffer[500] = "my age is 22\r\n\r\n and I live in Rostock"; // directly initialize the char array
const char sep[] = "\r\n\r\n";
char * p = strstr(buffer, sep); // search the separator
if (p) {
*p = '\0'; // null terminate the first part
p += strlen(sep); // make p point to the start of the second part
printf("%s - %s\n", buffer, p);
}
If you really need to purge the initial part from buffer and have it start at the second part, you could do:
for (char *dest = buffer; p<buffer+sizeof(buffer)-1;) { // do not go past end of array
*dest++ = *p++;
if (*p == '\0') break; // stop on first null
}

Save first word a file in c

I have a problem with this part of my code, I'm trying to read the lines of a file and cut only the first word of each line and then save it in an array.
Example:
two roads diverged in a yellow wood
and sorry i could not travel both
and be one traveler long i stood
and looked down one as far as i could
to where it bent in the undergrowth
and as a result I expect a vector like this: "two, and, and, and, to"
but I get this: "to, to, to, to, to".
My code
dictionary *load_word(int autor, dictionary *D_first)
{
FILE *date;
char line[LONG_MAX_LINE];
char exeption[4] = " \n\t";
char *word;
int j=0;
if (autor == 1)
{
if ((date = fopen("test.txt", "r")) == NULL)
{
perror("robert_frost.txt");
}
while (fgets(line, LONG_MAX_LINE, date ) != NULL)
{
word = strtok(line, exeption); /*first word*/
add_dictionary_first(D_first, j, word);
j++;
}
fclose(date);
}
return D_first;
}
void add_dictionary_first(dictionary *D, int cont, const char *value)
{
expand_dictionary(&D, 1);
D->Distribution[D->size-1]->cont = cont;
D->Distribution[D->size-1]->value = value;
}
The problem lies within this line (as Vlad from Moscow posted in the comments):
D->Distribution[D->size-1]->value = value;
This is just pointer assignment. That's not wrong per se, but depending on the
context, it is not what you want.
while (fgets(line, LONG_MAX_LINE, date ) != NULL)
{
word = strtok(line, exeption); /*first word*/
add_dictionary_first(D_first, j, word);
...
}
Here you call add_dictionary_first always with the same variable line. It is
an array but arrays decay into pointers when passing them as arguments to
functions. That means that all your D->Distribution[D->size-1]->value point to
the same location. The last line in your input file begins with to and that's why you get only
to.
You need to copy the string with strcpy.
man strcpy
#include <string.h>
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src, including the terminating
null byte ('\0'), to the buffer pointed to by
dest. The strings may not overlap, and the destination string dest must be
large enough to receive the copy.
Because you haven't posted the structure I can only guess that value is
declared as char* (if it were char[] the compiler would have complained).
Option 1
D->Distribution[D->size-1]->value = malloc(strlen(value) + 1); // note the +1 here
if(D->Distribution[D->size-1]->value == NULL)
{
// error handling
}
strcpy(D->Distribution[D->size-1]->value, value);
Option 2
If strdup is available in your system
D->Distribution[D->size-1]->value = strdup(value);
if(D->Distribution[D->size-1]->value == NULL)
{
// error handling
}
In either case you would have to free the memory later.

Using a character pointer array to store multiple char arrays

I have the following code in which I'm reading lines from a file and want to save them using a character pointer array. As I'm using one buffer inside my file read loop all my pointers in the character array end up pointing towards the last line read from file as the last line is the one that is currently held in the buffer when the loop terminates. How can I store them such that each pointer in the character array points to different char arrays in the order they were read.
int num_clients_to_start = 0;
char *token1, *token2, *str;
FILE* fp;
char bufr[256];
char testchar[255] = {};
char *start_client[10];
while(fgets(bufr, 256, fp) != NULL){
if(bufr[0] == '#'|| bufr[0] == '\n')
continue;
str = bufr;
token2 = ""; /* initializing an empty token 2 */
for(str = bufr; ;str = NULL){
token1 = strtok(str, " ");
if(strcmp(token2, "client_name") == 0){
sprintf(testchar,"%s", token1);
start_client[num_clients_to_start] = testchar;
num_clients_to_start++;
}
token2 = token1;
if(str == NULL){
break;
}
}//end of for loop
}//end of while loop
printf("client1 = %s client2 = %s client3 = %s",start_client[0],start_client[1],start_client[2]);
My input file is the following:
client_name abc
client_name def
client_name xyz
And print statement outputs:
client1 = xyz
client2 = xyz
client3 = xyz
Note that start_client[0], [1], [2] are all pointers to the last string (readed by fgets)
Use strdup in order to allocate them:
start_client[num_clients_to_start] = strdup(testchar);
As strdup can be an external identifier, use a prototype
#include <string.h>
char *strdup(const char *s);
And don't forget to free() at the end
You assign the same pointer to all entries in the start_client array. The array testchar will get different contents, but the pointer to it will always be the same. You might want to make start_client an array of arrays of char, and copy the string instead.
Like
char start_client[10][256];
And
strcpy(start_client[num_clients_to_start++], token1);

While Loop clearing my array? (C)

I've been hard at this problem for a bit and am wondering if anybody can find what Im doing wrong. Im reading user input from stdin, breaking up the string they input via strtok(), and storing it into an array of char *'s. The array of char *'s is defined outside of the while loop.
So: a user types in input via stdin, and an array is filled with strings with each word from the command.
The thing is, if the user simply hits enter I want the array to MAINTAIN it's value! I want the same values to stay in the array...so I can re-execute the same command. It appears that the while loop is clearing my array of char*'s instead. Here's code:
char *commands[3];
char *result = NULL;
char delims[] = " "; //a space AND a tab!
while (1) {
printf(PROMPT);
//Gathers user input!
char *input;
char stuff[230];
input = fgets(stuff, 230, stdin);
printf("input has length %i\n", strlen(input));
int helper = strlen(input);
int i = 0;
result = strtok(input, delims);
printf("helper has length %i\n", helper);
printf("commands[0] CHECK 1:%s", commands[0]);
if (helper >1)
{
while( result != NULL)
{
printf("while gets hit!\n");
if (i < 4)
{
commands[i] = result;
result = strtok(NULL, delims );
i++;
}
}
}
printf("commands[0] is CHECK 2:%s", commands[0]);
if (strncmp(commands[0], "step", 4) == 0)
{
lc3_step_one(p);
}
printf("commands[0] is CHECK 3:%s", commands[0]);
}
The printf's CHECK 1, CHECK 2,and CHECK 3 all print nothing if the user hits enter. In the case they last typed "step" I want "step" to stay in the array and thusly be executed again!
You are filling the commands array with pointers to the stuff array. That array is being overwritten by the fgets each time (probably replacing the first character with null). You would need to copy the data out to preserve it.

Resources