C parent child shared memory, prints without spacing - c

I am currently working on a lab for one of my classes that involves shared memory between a parent and child process. The data is generated by the child, and written into memory. The parent then prints the contents of the memory. My problem is that I cannot seem to get proper spacing between data points.
The algorithm used to generate data Collatz conjecture, which is n = n/2 if n is even, and n = 3*n+1 if n is odd. So an input of 8 would generate the sequence 8 4 2 1, but I keep getting "8421" or " 8421" or "8421 " ect.
I have tried many combinations of placement of spaces in both parent (printf) and child (sprintf). For example in the child:
sprintf(ptr, "%d", n);
sprintf(ptr, "%d ", n);
sprintf(ptr, " %d", n);
sprintf(ptr, " %d ", n);
and in the parent
printf("%s", (char *)ptr);
printf("%s ", (char *)ptr);
printf(" %s", (char *)ptr);
printf(" %s ", (char *)ptr);
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/mman.h>
int main(int argc, char** argv){
const int SIZE = 4096;//Shared memory size
const char* name = "COLLATZ";//Shaired Memory Name
int n = atoi(argv[1]);
pid_t pid = fork();//process divergence
int shm_fd;//shared memory file descriptor
void *ptr;//shared memory pointer
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);//create shared memory object
ftruncate(shm_fd, SIZE);//configure size of the shared memory
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);//memory map the shared memory object
if(pid == 0){
while(n > 1){//child
//write to shared memory
sprintf(ptr, "%d ",n);
char *a = (char *) &n;
ptr += strlen(a);
//Callatz conjecture sequence
if(n % 2 == 0){
n = n/2;
} else {
n = 3 * n+1;
}
}
//write to shared memory
sprintf(ptr, "%d ",n);
char *a = (char *) &n;
ptr += strlen(a);
}else if(pid > 0){//parent
wait(NULL);
printf("%s", (char *)ptr);//Read from shared memory
printf("\n");
}
shm_unlink(name);//close shared memory
return 0;
}

The issue is how you are adding to your ptr variable. setting a to (char*) &n will have a point to your int value, and since your int value is less than a 256 (a byte of memory), then it will be read as 1 char and read with length 1.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *ptr = malloc(4096);
int n = 12;
/// Writting to buffer section ///
sprintf(ptr, "%d ", n);
char *a = &n;
ptr += strlen(a);
//////////////////////////////////
// This should print "" if you added to ptr correctly
printf("\"%s\"", ptr);
fflush(stdout);
return 0;
}
output: "2 "
To fix this, you should use another way of adding to the pointer. My suggestion would be replacing the writting to buffer section with the following
int write_len = sprintf(ptr, "%d ", n);
ptr += write_len;
If you'd perfer not using the return value of spritnf, you can also do:
sprintf(ptr, "%d ", n);
ptr += strlen(ptr);

Notice that you add to the ptr only the lentgh of the number, and not the length of the entire string.
Change:
sprintf(ptr, "%d ",n);
char *a = (char *) &n;
ptr += strlen(a);
to:
char buff[100];
sprintf(buff, "%d ",n);
sprintf(ptr, "%s", buff);
ptr += strlen(buff);

Related

C - Multithreading count frequency of letters causes memory error

I'm trying to use C multithreading to find out the frequency of each alphabet letter in a text file. Assignment is to: 1) write a function that read every single sentence in a text, ended by '.' 2) write a function that load a sentence in a bidimensional array 3) write a function that generates a pthread for every letter for every sentence (pthread function add 1 to a counter for that letter).
EDIT: I figured out with Valgrind that the problem is in sentence function, by I dont understand why.
Here's the code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
char alphabet[26] = "abcdefghijklmnopqrstuvwxyz";
int count[26];
char* sentence(char * s){
char* p;
char* q;
char* arr;
int i;
p = s;
q = malloc(100);
arr = q;
for (i=0; *p != '.'; i++){
*q = *p;
q++;
p++;
}
*q = '\0';
return arr;
}
char** load_sentence(char* p, char** q, int i){
q[i] = malloc(strlen(p)+1);
strcpy(q[i], p);
return q;
}
void* count_letter(void * s){
char* p = (char*) s;
int i;
for (i=0; i<26; i++){
if (*p == alphabet[i]){
count[i]++;
}
}
}
void frequency(char* str){
char* s = str;
int i, j, l;
l = strlen(str);
pthread_t tid[l];
for (i=0; i<l; i++){
pthread_create(&tid[i], NULL, count_letter, (void*) s);
s++;
}
for (j=0; j<l; j++){
pthread_join(tid[j], NULL);
}
}
int main(int argc, char* argv[]){
int fd;
char buff[100];
fd = open(argv[1], O_RDONLY);
char ** text = malloc(10*sizeof(char*));
read(fd, buff, sizeof(buff));
char* start = buff;
int i = 0; //number of phrases!
char* p = NULL;
while (*(p = sentence(start)) != '\0'){
text = load_sentence(p, text, i);
start += strlen(p)+1;
i++;
}
int j, k;
for (k=0; k<i; k++){
frequency(text[k]);
}
for (j=0; j<26; j++){
printf("%c : %d times\n", alphabet[j], count[j]);
}
}
It looks like that with cases like this:
hope it's a good reading. bye.
The output is correct:
a : 2 times
b : 1 times
c : 0 times
d : 2 times
e : 3 times
f : 0 times
g : 3 times
h : 1 times
i : 2 times
j : 0 times
k : 0 times
l : 0 times
m : 0 times
n : 1 times
o : 3 times
p : 1 times
q : 0 times
r : 1 times
s : 1 times
t : 1 times
u : 0 times
v : 0 times
w : 0 times
x : 0 times
y : 1 times
z : 0 times
With others, a "memory error", that begins with free() : invalid next size (normal). The error has many lines of memory map and ends with abortion.
I'm quite new to C, sorry for my inexperience.
Is it necessary to introduce a mutex in this case?
Your previous version with mutex had undefined behaviour because you initialized mutex multiple times, according to reference:
Attempting to initialize an already initialized mutex results in
undefined behavior.
You are accesing count concurrently, so you have to use mutex to make thread-safe code. You called pthread_mutex_init in count_letter it is incorrect, this function is the body of your thread (multiple initialization of mutex without destroying it leads to UB), you should call pthread_mutex_init only once, for instance as first line in main function:
int main() {
pthread_mutex_init(&mtx,NULL);
before return add
pthread_mutex_destroy(&mtx);
Critical section in your count_letter function is line
count[i]++;
you should modify it as follows
pthread_mutex_lock(&mtx);
count[i]++;
pthread_mutex_unlock(&mtx);
Now, return to sentence implementation, you need to check if *p doesn't point to null terminator before comparing with .:
for (i=0; *p && *p != '.'; i++){
^^ added
without testing it, \0 != . returns true and your loop continues ...
Erika,
Since I don't really know your assignment please see this as just another way out of a 1000 to count characters. I have not checked it for bugs, rewrite to your needs. Anyhow this is how I would have solved it. If memory is sparse I would read character by character from the file until ".". Anyhow hope it helps you and you get great grades :-)...
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdatomic.h>
#define MAX_THREADS 100
atomic_int threadCount;
#define NCHAR 26
char alphabet[NCHAR] = "abcdefghijklmnopqrstuvwxyz";
atomic_int count[NCHAR];
void* count_letter(void * s){
threadCount++;
char* p = (char*) s;
for (int i=0; i<NCHAR; i++)
if (*p == alphabet[i])
count[i]++;
threadCount--;
return NULL;
}
int main(int argc, char* argv[]){
//Init variables
FILE *file;
char *myText;
unsigned long fileLen;
int deadLockGuard=0;
threadCount=0;
//Open the file
file = fopen(argv[1], "rb");
if (!file) {
fprintf(stderr, "Unable to open file %s", argv[1]);
return EXIT_FAILURE;
}
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
rewind(file);
//reserve memory and read the file
myText=(char *)malloc(fileLen+1);
if (!myText) {
fprintf(stderr, "Memory error!");
fclose(file);
return EXIT_FAILURE;
}
fread(myText, fileLen, 1, file);
fclose(file);
//Get each sentence ending with a . and then for each character look at the count for each character in it's own thread.
char *subString = strtok(myText, "."); //This is your sentence/load_sentence method
while (subString != NULL) {
for (int v = 0;v<strlen(subString);v++) { //This is your frequency method
deadLockGuard=0;
while (threadCount >= MAX_THREADS) {
usleep(100); //Sleep 0.1ms
if(deadLockGuard++ == 10000) {
printf("Dead-lock guard1 triggered.. Call Bill Gates for help!"); //No free threads after a second.. Either the computer is DEAD SLOW or we got some creepy crawler in da house.
return EXIT_FAILURE;
}
}
pthread_t tid; //Yes you can overwrite it.. I use a counter to join the workers.
pthread_create(&tid, NULL, count_letter, (void*) subString+v);
}
subString = strtok(NULL, ".");
}
deadLockGuard=0;
//pthread_join all the still woring threads
while (threadCount) {
usleep(1000); //sleep a milli
if(deadLockGuard++ == 2*1000) {
printf("Dead-lock guard2 triggered.. Call Bill Gates for help!"); //Threads are running after 2 seconds.. Exit!!
return EXIT_FAILURE;
}
}
//Garbage collect and print the results.
free(myText);
for (int j=0; j<NCHAR; j++)
printf("%c : %d times\n", alphabet[j], count[j]);
return EXIT_SUCCESS;
}

C: Losing strings when exiting functions

I'm trying to implement a basic shell, I have several functions within it that deal with strings, trying to find file names, implement something equivalent to *argv[] and so on.
I have strings in main(), which are passed to a function to be populated. Next the program returns to main(), which passes the strings to another function to be acted upon.
I was debugging with lldb and found that I was successfully populating the strings with the correct values in the first function but upon exiting the function, re-entering main() the output_str string was NULL again. I thought strings, since they point to space in memory would retain values. They seem to for all but one case, when flag = 1 in the code below.
I can't figure out what's happening as the values seem to only be lost after the final } of the function.
Edited to add complete code, hope it isn't too large.
The code works with say, cat input.txt but not with cat input.txt>output.txt when I try to redirect the output from stdout to a file
Thank you for your help in advance.
Here is the function .c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
void sig_handler(int signo)
{
if (signo == SIGINT)
{
fprintf(stdout, "\n");
fflush(stdout);
}
}
int check_redirect(char *line, int flag)
{
int n = 0;
if (line == NULL) return (flag);
else
{
do
{
if (line[n] == '>') flag = 1;
n++;
}while (line[n] != '\0');
}
return (flag);
}
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *sep = " \n";
char *delim = ">\n";
if (line != NULL)
{
temp = strtok(line, delim);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
temp = strtok(NULL, delim);
}
if (flag)
{
count = 0;
strcpy(filename, output_str[1]);
output_str[1] = NULL;
*saved_stdout = dup(1);
*f = open(filename , O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(*f, 1);
temp = strtok(*output_str[0], sep);
while (temp != NULL)
{
output_str[count] = temp;
//if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
else
{
count = 0;
temp = strtok(line, sep);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
}
}
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *command = malloc(sizeof(char *));
command = output_str[0];
char *name = "HOME";
int ret_val = 0;
pid_t child_pid;
int child_status;
if (command == NULL);
else if (strcmp("cd", command) == 0)
{
if (output_str[1] == NULL) output_str[1] = getenv(name);
ret_val = 0;
ret_val = chdir(output_str[1]);
if (ret_val) perror(NULL);
}
else
{
child_pid = fork ();
if (child_pid == 0)
{
if (debug)
{
system(line);
fprintf(stderr, "Post System Pre Exec\n1:%s\n2:%s\n3:%s\n", line, output_str[0], command);
sleep(2);
}
execvp(command, output_str);
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
fprintf (stdout, "Unknown command\n");
exit (0);
}
else
{
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
signal(SIGINT, sig_handler);
usleep(500000);
//Parent process waits for child to finish
if (debug) fprintf (stderr, "parent waiting\n");
wait(&child_status);
waitpid(child_pid, &child_status, 0);
signal(SIGINT, SIG_DFL);
}
}
Here is the functions .h file:
#ifndef SHELL_H_INCLUDED
#define SHELL_H_INCLUDED
void sig_handler(int signo);
int prompt(char *line, size_t len, ssize_t read);
int check_redirect(char *line, int flag);
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug);
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug);
#endif // LINKLAYER_H_INCLUDED
Below is main.c, where the function is called.
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "shell.h"
int main(void)
{
int debug = 0;
char *line = NULL;
size_t len = 0;
ssize_t read = 0;
int flag = 0;
int f = 0;
int saved_stdout = 0;
do
{
flag = 0;
//read = prompt(line, len, read);
char buffer[15];
time_t now = time(NULL);
strftime(buffer, 15, "[%d/%m %H:%M]", localtime(&now) );
fprintf(stdout, "%s # ", buffer);
signal(SIGINT, SIG_IGN);
read = getline (&line, &len, stdin);
signal(SIGINT, SIG_DFL);
flag = check_redirect(line, flag);
char **output_str = malloc(sizeof(char *));
int count = 0;
char* temp = NULL;
char *filename = malloc(sizeof(char *));
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // function call of problem function
com_exec(line, output_str, filename, &f, &saved_stdout, flag, debug);
} while (read != EOF);
if (debug) fprintf(stderr, "parent exiting\n");
else fprintf(stdout, "\n");
return 0;
}
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
This line re-assigns the value of the the local parameter variable output_str, but the new value in no way makes it back to the caller of the string_breakdown function - meaning that the pointer it has will probably be left dangling, and will cause problems when used ("undefined behavior", manifesting in strange program behavior or crashing).
You need to understand that within the function, output_str is a local variable. You can change its value, but that won't affect the value of any variable in the caller.
You call the function from main:
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
main also uses output_str as the variable name, but again, this is a different variable. One variable is local to main, the other is local to string_breakdown, even though they share the same name. Due to the realloc call above, the pointer value in main's output_str will most likely be invalid on return from string_breakdown, because it is not updated to point to the newly allocated memory. That's why you are "losing" the string values on return from the function - the output_str variable in main is no longer actually pointing to the array of strings, which has been moved to a different location via realloc.
Typically you resolve this kind of problem by adding another level of indirection, changing the output_str parameter from a char ** to a char ***:
void string_breakdown(char *line, char ***output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
and
(*output_str)[count] = temp;
and
*output_str = realloc (*output_str, (count + 1) * sizeof (char *) );
and so on. You need to adjust the call in main as well:
string_breakdown(line, &output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
Because you are passing a pointer to main's output_str variable, the called function is now able to modify its value.
You should also understand that string_breakdown as written modifies the string which the line parameter points to. That's because it uses strtok, and strtok replaces delimiters with nul bytes as it processes the string. So, it is odd that you pass this modified line buffer to com_exec after processing it with string_breakdown.
I get several warnings when I try to compile your code; main.c uses fprintf but doesn't #include <stdio.h>, and uses malloc but doesn't #include <stdlib.h>.
your realloc does nothing.
you mean *output_ptr = realloc....
actually it does something, but its really bad
this is also wrong
output_str[count] = temp;
and this
filename = output_str[1];
you need to distinguish - a pointer to your buffer, a pointer to the pointer to your buffer.
char * buffer = *output_str; // to remove the confusion
strcpy(&buffer[count], temp); // assigning pointers doesnt copy things
filename = buffer[1]; // is hat what you mean - filename is one char

System call execve does not return with ls function

I am asked to implement my own shell for an Operating System class.
My shell runs every commands fine, except ls that won't return on execve, which is weird because cd, cp, mv, and all the others main commands are returning okay.
ls is still displaying the right output (the list of files in the folder), but just keep running after (execve hangs and needs a carriage return to finish).
All the options like -l, -a are also working correctly, with the same issue.
EDIT: I modified my code in order to completely avoid any memory leaks (I used valgrind to track them), added some comments so you can see what's going on, but ls is still not returning. Here is the updated version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAXPATHLEN 40
#define MAXSIZE 100
#define MAXARGS 10
static char cwd[MAXPATHLEN];
typedef void (*sighandler_t)(int);
void handle_signal(int signo);
void parse_command(char *command, char **arguments);
int main(int argc, char *argv[], char *envp[])
{
int status;
char *command;
char **arguments;
signal(SIGINT, SIG_IGN);
signal(SIGINT, handle_signal);
while(1) {
//Allocating memory
command = calloc(MAXSIZE, sizeof(char));
arguments = calloc(MAXARGS, sizeof(char *));
//Print shell name and cwd
getcwd(cwd,MAXPATHLEN);
printf("[MY_SHELL]:%s$ ", cwd);
parse_command(command, arguments);
//Displays command and arguments
printf("Command is %s\n", command);
int i;
for(i=0; arguments[i] != NULL; ++i){
printf("Argument %d is %s\n", i, arguments[i]);
}
//Fork exec code
if (fork() != 0){
waitpid(1, &status, 0);
} else{
execve(command, arguments, 0);
}
free(command);
for (i=0; arguments[i] != NULL; ++i) {
free(arguments[i]);
}
free(arguments);
}
return 0;
}
void handle_signal(int signo)
{
getcwd(cwd,MAXPATHLEN);
printf("\n[MY_SHELL]:%s$ ", cwd);
fflush(stdout);
}
void parse_command(char *command, char **arguments){
char buf[MAXSIZE];
char env[MAXPATHLEN];
char *tmp;
//Initiate array values to avoid buffer overflows
memset(buf, 0, sizeof(buf));
memset(env, 0, sizeof(env));
//Read command and put it in a buffer
char c = '\0';
int N = 0; //Number of chars in input - shouldn't be more than MAXSIZE
while(1) {
c = getchar();
if (c == '\n')
break;
else{
if (N == MAXSIZE)
break;
buf[N] = c;
}
++N;
}
//Extract command name (e.g "ls"), fetch path to command, append it to command name
tmp = strtok(buf, " ");
strcpy(env, "/bin/");
size_t len1 = strlen(env);
size_t len2 = strlen(tmp);
memcpy(command, env, len1);
memcpy(command + len1, tmp, len2);
//Extracts arguments array: arguments[0] is path+command name
arguments[0] = calloc(strlen(command) + 1, sizeof(char));
strcpy(arguments[0], command);
int i = 1;
while(1){
tmp = strtok(NULL, " ");
if (tmp == NULL)
break;
else{
arguments[i] = calloc(strlen(tmp) + 1, sizeof(char));
strcpy(arguments[i],tmp);
++i;
}
}
}
EDIT 2: This seems to have something to do with STDIN (or STDOUT): similarily than ls, cat makes execve hangs after executing, and I need to carriage return to have my shell line [MY_SHELL]current_working_directory$: line back. Any thoughts on why it is the case ?
In your code, in parse_command() function, you're doing
bzero(arguments, sizeof(char) * MAXARGS);
but at that point of time, arguments is not initialized or allocated memory. So essentially you're trying to write into uninitialized memory. This invokes undefined behaviour.
Same like that, without allocating memory to arguments, you're accessing arguments[0].
Note: As I already mentioned in my comments, do not cast the return value of malloc() and family.
C uses pass by value. That means that after the call to parse_command the value of arguments will still be undefined, since any assignments were made to the local copy. Instead of becoming a three-star programmer I would recommend that you have parse_command return the argument list instead:
char **parse_command(char *command){
char **arguments = malloc(...);
...
return arguments;
}
And in main:
arguments = parse_command(command);
Also look at Sourav Ghosh's answer as he points out some other bugs.

sizeof(table)/sizof(table[0]) not working

H i am building a basic shell in c and i need to know the size of the array i am populating with user input. Here is the code.
/*
* Tp1.c
*
* Created on: 25 janv. 2014
* Author: shong
*/
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
void cd_handler(int argc, char *argv[]);
int lire(char *chaine, int longueur);
char** init_command(char *str);
int main(int argc, char *argv[]) {
//printf("La valeur de argc est: %d", argc);
while(1){
printf("Log710H2014%>");
char str[200];
lire(str, 200);
char** comms = init_command(str);
printf("%s", comms[1]);
if(strcmp(comms[0], "cd") == 0){
int commArgsC = sizeof(comms)/sizeof(comms[0]);
cd_handler(commArgsC, comms);
}else if (strcmp(comms[0], "exit") == 0){
exit(0);
}
}
}
}
void cd_handler(int argc, char *argv[]){
char cwd[256];
char * directory;
if(argc < 2){
directory = getenv("HOME");
}else if (argc == 2){
directory = argv[1];
}else{
exit(1);
}
if (chdir(directory) == -1) {
printf ("chdir failed - %s\n", strerror (errno));
}else{
if (getcwd(cwd, sizeof(cwd)) == NULL)
perror("getcwd() error");
else
printf("current working directory is: %s\n", cwd);
}
}
char** init_command(char* str){
char ** res = NULL;
char * p = strtok (str, " ");
int n_spaces = 0, i;
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL){
exit (-1);
}
res[n_spaces-1] = p;
p = strtok (NULL, " ");
}
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
//print the result
//for (i = 0; i < (n_spaces+1); ++i)
//printf ("res[%d] = %s\n", i, res[i]);
//free the memory allocated
//free (res);
return res;
}
int lire(char *chaine, int longueur)
{
char *positionEntree = NULL;
if (fgets(chaine, longueur, stdin) != NULL)
{
positionEntree = strchr(chaine, '\n');
if (positionEntree != NULL)
{
//*positionEntree = '\0'; // On remplace ce caractère par \0
}
return 1;
}
else
{
return 0; // on renvoie 0 s'il y a eu une erreur
}
}
The problem is that sizeof(comms) always return 8, no matter the number of elements in comm.
comms is a pointer, so on a 64-bit machine it will have a size of 8 bytes. C has no knowledge about the size of what it points to. You'll have to return the size from the function that allocates the storage and keep track of it yourself.
The behavior sizeof is dependent on what type of variable it is applied to.
If the variable is a pointer, as in the question, sizeof simply evaluates to the size of the pointer type in bytes:
int *y; //y points to an int... maybe an array? Who knows?
printf("%d",sizeof(y)); //No idea how y has been allocated. Defaults to sizeof(int*)
If the variable was declared as an array, sizeof returns the size of the entire array. For instance:
int y[4]; //y is exactly four ints in memory
printf("%d",sizeof(y)); //sizeof knows this, and evaluates to sizeof(int)*4
This is why the sizeof(table)/sizeof(table[0]) would work for an array. However, it does not work pointers as demonstrated above. In short, passing an array as an argument destroys any information regarding how much data is in that array, and you must pass the size separately. This is referred to as "array decay."
The difference between pointers and arrays is very subtle. Most of the time, the two can be used interchangeably, but there are two critical differences:
The difference in the behavior of sizeof as discussed previously.
Arrays cannot be assigned as pointers can. This relates to the fact that they are of constant size. For instance:
char **table;
//table can be assigned different values....
table = NULL;
//...multiples times, if wanted
table = malloc(sizeof(char*)*20);
However,
//table is constant
char *table[20];
//it's individual elements can be assigned as usual...
table[0] = malloc(1);
//...but attempts to change where table points to will fail
table = NULL; //This will cause a compilation error.

Why does the following code raise a SegFault. c(Linux)

This a code that would reverse the data of a document and save it in the same document itself.
However I am getting a Segmentation Fault.Please Help,I don't know why it gives a SegFault.
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main (int argc,char* argv[])
{
int fd,n,i,j;
char* buf;
if(argc<2)
printf("USAGE: %s file-to-reverse.\n",argv[0]);
fd=open(argv[1], O_RDWR);
if(fd==-1)
printf("ERROR: Cannot reverse %s,file does not exist.\n",argv[1]);
i = 0;
j = n-1;
while(i < j)
{
read(fd,buf,n);
char ib = buf[i];
char jb = buf[j];
jb = i++;
ib = j--;
write(fd,buf,n);
}
free(buf);
close(fd);
}
EDIT1
I tried adding :
#include <sys/stat.h>
struct stat fs;
fstat(fd, &fs);
n= fs.st_size;
buf = malloc(n * sizeof (char));
but now it just duplicates the characters inside the document again and again instead of
reversing them.
You don't allocate, nor initialize buf.
You never initialized n so it could be anything, even negative. Use fstat or some other method to determine the size of the file and store that in n.
Your buffer isn't allocated and n = 0 so you will try to read 0 chars.
This should repair your code :
buf = malloc(10 * sizeof (char));
n = 10;
Resources :
Wikipedia - malloc()
linux.die.net - malloc()
linux.die.net - read()
Regarding your second EDIT - your loop is wrong.
(1) Take the read & write out of the loop - that's why it keeps writing again & again.
(2) You need to seek back to the beginning of the file, otherwise you will just be appending the new data to the end of the file.
(3) You actually have to reverse the chars in the buffer before writing them out.
read(fd, buf, n);
while (i < j)
{
char t = buf[i];
buf[i] = buf[j];
buf[j] = t;
i++;
j--;
}
lseek(fd, 0, SEEK_SET);
write(fd, buf, n);

Resources