Vincent Normand Vincent Normand - 20 days ago 7
C Question

How to add NULL to an array of string in C

I'm trying to add NULL to a string to make execvp work.
Here is my code :

void execCmd(char *cmd[]){
int count = 0;
while(strcmp(cmd[count],NULL) != 0) count++;
cmd[count] = NULL;
execvp(cmd[0], cmd);
perror("execvp");
}


here is my body code. It works with pipe. Tell me if you need my client code too (even if I'm pretty sure it won't be useful because it works)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#define TAILLE_CHAINE 15500
int isPalindrome(char *t);
void execCmd(char *cmd[]);
void RemoveSpaces(char* source);
char *replace(const char *s, char ch, const char *repl);
int main()
{
char tube_serveur[TAILLE_CHAINE]="tube_serveur.fifo";
int sortieTube; /* pointera sur la sortie du tube serveur */
int entree_tube;/* pointera sur le tube client */
char chaineALire[TAILLE_CHAINE];/*chaine à lire dans le tube serveur*/
char chaineAEcrire[TAILLE_CHAINE]; /*chaine à écrire dans le tube du client*/
char **chaineCmd = malloc(sizeof(char*) * (250));
char *tube_client;/*un pointeur pour la fonction strtok (chaineALire, ";") qui permet de segmenter chaineALire */
char *mot;/* mot que le client veut tester si c'est un palindrome ou non */
int i =0;
do
{ /***************** création tube serveur **********************/
if(mkfifo(tube_serveur, 0644) != 0)
{ fprintf(stderr, "Impossible de créer le tube nommé.\n");
exit(EXIT_FAILURE);
}
/**************** Attente d'un appel client ******************/
if((sortieTube = open (tube_serveur, O_RDONLY)) == -1)
{
fprintf(stderr, "Impossible d'ouvrir la sortie du tube nommé.\n");
exit(EXIT_FAILURE);
}
read(sortieTube, chaineALire, TAILLE_CHAINE);
unlink(tube_serveur);
printf("%s\n", chaineALire);
tube_client = strtok (chaineALire, ";");/* segmente la chaine par le séparateur ; donc tube_client vaut le nom du tube du client (1ère partie de la chaine)*/
mot = strtok (NULL, ";");
if ((strcmp(mot,",") == 0) || (strcmp(mot, "stop") == 0))/*Si le mot vaut FIN on le serveur inutile d'utiliser la fonction de palindrome */
{
execCmd(chaineCmd);
int k =0;
chaineCmd = NULL;
chaineCmd = malloc(sizeof(char*) * (250));

}
if (strcmp(mot,"stop") == 0)/*Si le mot vaut FIN on le serveur inutile d'utiliser la fonction de palindrome */
{
memset( chaineAEcrire, '\0', sizeof(chaineAEcrire) );
sprintf(chaineAEcrire,"Fin du serveur");
//break;
}
chaineCmd[i] = malloc((strlen(mot) + 1) * sizeof(char));
strcat(chaineCmd[i], mot);
printf ("client : %s\n", tube_client);
printf ("message : %s\n", mot);
/************* Ecriture dans le tube client ********/
unlink(tube_client);/*on détruit le dernier tube client*/
if(mkfifo(tube_client, 0644) != 0)
{ fprintf(stderr, "Impossible de créer le tube nommé.\n");
exit(EXIT_FAILURE);
}
if((entree_tube = open(tube_client, O_WRONLY)) == -1)
{ fprintf(stderr, "Impossible d'ouvrir l'entrée du tube nommé.\n");
exit(EXIT_FAILURE);
}

else
{
if(isPalindrome(mot))/* Le mot est-il un palindrome? */
{ memset(chaineAEcrire, '\0', sizeof(chaineAEcrire) );/*remplace toutes les cases de la chaine par \0 : vide la chaine*/
sprintf(chaineAEcrire,mot);/*on écrit le mot dans la chaine*/
strcat(chaineAEcrire, " est un palaindrome."); /* on indique que c'est un palindrome */
}
else
{ memset( chaineAEcrire, '\0', sizeof(chaineAEcrire) );
sprintf(chaineAEcrire,mot);
strcat(chaineAEcrire, " n'est pas un palaindrome.");
}
}
write(entree_tube,chaineAEcrire, TAILLE_CHAINE);/* réponse au client */
i++;
}
while((strcmp(mot,"stop") != 0) );
/************** Programme terminé *****************************/
unlink(tube_serveur);
printf("fin du serveur");
return EXIT_SUCCESS;
}
int isPalindrome(char *t)
{ int i;/*emplacement de la lettre en commencant par le début (ex : t[0] puis t[1]...*/
int j;/*emplacement de la lettre en commencant par le début (ex : t[n] puis t[n-1]...*/
int n=strlen(t); /* taille de la chaine */
for(i=0,j=n-1;i<j;i++,j--)
{ if(tolower(t[i])!=tolower(t[j])) /*on met en minuscule car A!=a or Anna est un palindrome */
{ return 0;/*ce n'est pas un palindrome*/
}
}
return 1;
}
void execCmd(char *cmd[]){
execvp(cmd[0], cmd);
perror("execvp");
}
char *replace(const char *s, char ch, const char *repl) {
int count = 0;
const char *t;
for(t=s; *t; t++)
count += (*t == ch);

size_t rlen = strlen(repl);
char *res = malloc(strlen(s) + (rlen-1)*count + 1);
char *ptr = res;
for(t=s; *t; t++) {
if(*t == ch) {
memcpy(ptr, repl, rlen);
ptr += rlen;
} else {
*ptr++ = *t;
}
}
*ptr = 0;
return res;
}


How can I do this?

Thanks for helping

Answer

execvp() expects the last element to be a NULL pointer, not a \0 char to signal the end.

You call it like this:

static int example(const char * binary, int num_argv, char * argv[])
{
    argv[num_argv - 1] = NULL; /* ensure argv is NULL terminated. */
    int r = execvp(binary, argv);
    if(r < 0) // execvp() failed
    {
        perror("failed to execvp()");
        /* 
         * terminate the current process regardless
         * otherwise you could end up with a process stuck in limbo
         * which is particularly troublesome if you rely on 
         * a simple fork() + some kind of wait() in a parent process
         * to cleanup child processes
         */
        exit(255);
    }
    return r;
}