I am trying to create a thread and read from stdin inside the thread. In main() have dynamically allocated memory to a 2d array based on the size given as user input. In the thread I am reading from stdin and splitting it using strtok and adding it into the 2d array. I am not sure why there is a segmentation fault, searched SO and I seem to have handled all the cases related to strtok.
This is the program -
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int dimB;
int dimA;
char** buffer;
char* temp;
void *thread(void *threadid){
char *buf;//[30] = {};
size_t len = 0;
ssize_t read;
char *line = NULL;
char *each;
printf("Hello World!.\n");
while ((read = getline(&line, &len, stdin)) != -1) {
printf("%s || \n", line);
each = strtok(line," ,()");
printf("************************%s ", each);
while(each != NULL){
buf = each;
strcpy(buffer[0][0], buf);
printf("%s", buf);
each = strtok(NULL," ,()");
}
}
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t tidMpr;
long r;
int i;
dimB = atoi(argv[1]);
dimA = atoi(argv[2]);
pthread_t tidRdr[dimA];
buffer = malloc(dimA * sizeof(char*));
temp = malloc(dimA * dimB * sizeof(char));
for (i = 0; i < dimA; i++) {
buffer[i] = temp + (i * dimB);
}
//Create thread Thread
pthread_create(&tidMpr, NULL, thread, NULL);
free(temp);
free(buffer);
pthread_exit(NULL);
}
The 2d array memory allocation is from this question - How do I work with dynamic multi-dimensional arrays in C?.
I know I am writing everything to buffer[0][0], but that is so that I can store each in a buffer array buffer[0][1], buffer[0][2] later on based on some logic. But that shouldn't be a problem now right?
Also line is printing the correct value, whatever it is reading from stdin. So, probably strtok is the problem.
Another very similar program produces the desired output. This -
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
typedef struct { char action; int score; } Rules;
Rules rules[5] = {{'P',50}, {'L',20}, {'D',-10}, {'C',30}, {'S',40}};
int findScore(Rules* rules, char action){
int i;
for(i=0; i<5; i++){
if(rules[i].action == action)
return rules[i].score;
}
fprintf(stderr, "Action not present! Exiting...\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]){
FILE *fp;
char inputTuple[30] = {};
char buf[30] = {};
char* oB;
oB = "(";
char* cB;
char* co = ",";
cB = ")";
fp = fopen(argv[1], "r");
int score;
char *each;
size_t len = 0;
ssize_t read;
char * line = NULL;
char *eacharray;
int u = 0;
char *outputTuple;
int pad = 0;
int g;
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
each = strtok(line," ,()");
while(each != NULL){
if(u%3 == 0){
outputTuple = (char *) malloc(1 + strlen(each)+ strlen(oB) );
strcpy(outputTuple, oB);
strcat(outputTuple, each);
} else if(u%3 == 1){
char q = *each;
score = findScore(rules, q);
} else if(u%3 == 2){
char * str3 = (char *) malloc(1 + strlen(outputTuple)+ strlen(co) );
strcpy(str3, outputTuple);
strcat(str3, co);
char *str4 = (char *) malloc(1 + strlen(str3)+ strlen(each) );
strcpy(str4, str3);
strcat(str4, each);
for(pad = strlen(each); pad<15; pad++)
strcat(str4," ");
sprintf(buf, "%s,%d)\n", str4, score);
printf("%s", buf);
free(outputTuple);
free(str3);
free(str4);
}
each = strtok(NULL," ,()");
u++;
}
u = 0;
}
fclose(fp);
return 0;
}
Update :
strcpy(buffer[0][0], buf); seems to be the problem. When I comment it, it is producing the output. I dont understand why is that causing a problem.
Related
I have a working example of copy lines from a file into an array of strings. I want to move the code to copy the lines into a function to which I simply pass a pointer to the array of strings, where the lines will be stored, and a pointer to the file. However, I have tried to move the code into a function and keep getting seg faults. I have tried debugging using GDB and it seems like the problem is with the memory allocation to rows. But I can't work out what the problem is. realloc seems to be working correctly since I find the size of row increases on the 3rd iteration (using malloc_usable_size(*rows)), but then seg faults. I'm compiling with gcc -Wall -Wextra -pedantic -std=c99 -g c_programs/read_file_function.c on Linux.
Working example
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
rows[i] = (char *)malloc(lineLength + 1);
strcpy(rows[i], lineBuf);
i++;
nLines = i;
rows = (char **)realloc(rows, (nLines + 1) * sizeof(char *));
}
printf("nLines: %lu\n", nLines);
printf("row 1: %s\n", rows[0]);
printf("row 2: %s\n", rows[1]);
printf("row 2: %s\n", rows[10]);
return 0;
}
Non working function version
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t readFile(FILE **fp, char ***rows)
{
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, *fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
*rows[i] = (char *)malloc(lineLength + 1);
strcpy(*rows[i], lineBuf);
i++;
nLines = i;
*rows = (char **)realloc(*rows, (nLines + 1) * sizeof(char *));
}
return nLines;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
size_t nLines = readFile(&fp, &rows);
printf("nLines: %lu", nLines);
printf("row 1: %s", rows[0]);
printf("row 2: %s", rows[1]);
return 0;
}
*rows[i] is doing *(rows[i]) - accessing ith element in the array of rows, and then dereferencing it. You want to do (*rows)[i] - dereference rows and then access ith element.
I advise to:
readFile(..., char ***rows0) {
char **rows = NULL; // temporary internal variable
...
// use rows normally
rows = stuff();
...
// when finished, assign once
*rows0 = rows;
return nLines;
}
But do not be a 3-star programmer. At best, use a structure, -> is easy to use. Like:
struct string {
char *str;
};
struct lines {
struct string *strs;
size_t cnt;
};
// #return 0 on success, otherwise error
int readFile(...., struct lines *p) {
// initialization
p->cnt = 0;
p->strs = NULL;
...
void *pnt = realloc(p->strs, (p->cnt + 1) * ....);
if (!pnt) { /* handle error */ return -1; }
p->strs = pnt;
p->strs[p->cnt]->str = malloc(lineLenght + 1);
if (!p->strs[p->cnt]->str) { /* handle error */ return -2; }
strcpy(p->strs[p->cnt]->str, lineBuf);
p->cnt++;
...
return 0; /* success */
}
int main(int argc, char **argv) {
struct lines p = {0};
if (readFile(..., &p)) {
/* handle error */
}
printf("nLines: %zu\n", p.cnt);
Do not pre-allocate memory. Initialize memory with NULL and call realloc before using memory. realloc(NULL is the same as malloc().
Check for allocation errors.
This question already has answers here:
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 1 year ago.
I have quite a big dictionary file. I want to take each line from the file and store it in an array so I can perform manipulations later. For example given the words:
aaaa
arggghhh
broooooo
Coooodee
If I call array[2], it should give me "broooooo". I have tried using the code below however I keep running into segmentation faults. Any help would be greatly appreciated.
Here is the code I have been trying:
int main (int argc, char* argv[]) {
char* file="/usr/share/dict/words";
FILE *dict;
char str[60];
char arr[80368][60];
int count = 0;
dict = fopen(file, "r");
if(dict == NULL){
perror("Error opening file");
return(-1);
}
while(fgets(str,sizeof(str),dict) != NULL){
strcpy(arr[count], str);
count++;
}
fclose(dict);
return 0;
}
char arr[80368][60];
This will try to allocate 4822080 bytes on the stack. The default maximum should be 8Mb so it is lower than that, but maybe it is configured lower on your system? You can inspect with ulimit -a | grep stack.
Does your program work if you test with a smaller input file, say generated with head -100 /usr/share/dict/words > input.txt, and then with the size of arr reduced correspondingly?
This is the best method to read file when you don't know the size.
If you want the file inside array you just need to use str_split else the file is inside char *
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fcntl.h>
#include <stddef.h>
char **str_split(char *cmd, char split_by)
{
char **argv = malloc(sizeof(char *) * strlen(cmd));
int pos = 0;
for (int i = 0; cmd[i] != '\0'; i++) {
if (cmd[i] == split_by || cmd[i] == '\0') {
cmd[i] = '\0';
argv[pos] = strdup(cmd);
pos++;
cmd += i + 1;
i = 0;
}
}
argv[pos] = strdup(cmd);
argv[pos + 1] = NULL;
return argv;
}
char *load_file(char *file_path)
{
int fd;
struct stat file_stat;
stat(file_path, &file_stat);
int file_size = file_stat.st_size;
char *str = malloc(sizeof(char) * file_size + 2);
if ((fd = open(file_path, O_RDONLY)) == -1) {
printf("error");
exit(84);
}
read(fd, str, file_size);
str[file_size] = '\0';
return str;
}
int main(int ac, char **av)
{
char *file_in_string = load_file(av[1]);
printf("this is the file in one string:\n%s\n", file_in_string);
char **file_in_array = str_split(file_in_string, '\n');
printf("this is the file inside array");
for (int i = 0; file_in_array[i]; i++)
printf("line [%d]: %s\n", i, file_in_array[i]);
}
There is probably more issues at hand, but for now my problem is that when I compile and run this like so:
cc -o parser parser.c
./parser
I expect it to open a particular file, read from it, and parse it. However, it seems to expect me to provide input and I have to Ctrl-C to kill it. Am I using fgets wrong? I tried getline() with the same results. I added the puts() to make sure it was reading what I expected and it does. Any help is appreciated.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *fp;
char buf[1024];
char *tmp, *pattern, *dir;
char *skip, *p;
char *tok[5];
char **ap;
size_t sz = 0;
ssize_t len;
int i;
int action = 0; // placeholder
int fileinto = 1; // placeholder
char path[PATH_MAX] = "/home/edgar/.patfile";
fp = fopen(path, "r");
if (fp == NULL)
fprintf(stderr, "fopen failed");
while (fgets(buf, sizeof(buf), fp) != NULL) {
buf[strcspn(buf, "\n")] = '\0';
// skip comments
for (skip = buf; *skip; ++skip) {
if (*skip == '#') {
*skip = '\0';
break;
}
}
// skip empty lines
if (strlen(buf) == 0)
continue;
puts(buf); // debug only
// make a copy
tmp = strdup(buf);
for (i = 0, ap = tok; ap < &tok[4] && (*ap = strsep(&tmp, " ")) != NULL; i++) {
if (**ap != '\0')
ap++;
}
while (i >= 0) {
if(tok[i] == "match")
pattern = tok[i + 1];
if(tok[i] == "fileinto") {
action = fileinto;
dir = tok[i + 1];
}
}
}
free(tmp);
fclose(fp);
exit(0);
}
In the below code, the file test.txt has the following data :
192.168.1.1-90
192.168.2.2-80
The output of this is not as expected. I expect the output to be
192.168.1.1
90
192.168.2.2
80
The current output is
192.168.2.2
80
192.168.2.2
80
I know that the pointer of str is pointing to the same address in the second iteration as well.
Im just not able to the problem.
Any help would be appreciated.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE * fp;
char * result[10][4];
int i = 0;
const char s[2] = "-";
char temp[50];
char * value, str[128], * string, t[20], x[29] = "192.168.2.2";
fp = fopen("test.txt", "r");
if (fp == NULL)
printf("File doesn't exist\n");
else {
while (!feof(fp)) {
if (fgets(str, sizeof(str), fp)) {
/* get the first value */
value = strtok(str, s);
result[i][0] = value;
printf("IP : %s\n", result[i][0]); //to be removed after testing
/* get second value */
value = strtok(NULL, s);
result[i][1] = value;
printf("PORT : %s\n", result[i][1]); //to be removed after testing
i++;
}
}
for (int k = 0; k < 2; k++) {
for (int j = 0; j < 2; j++) {
printf("\n%s\n", result[k][j]);
}
}
}
return (0);
}
I propose like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { IP = 0, PORT = 1};
int main(void){
FILE *fp;
char result[2][2][16];//2 lines, 2 kinds, 16:XXX.XXX.XXX.XXX+NUL
const char *s = "-";//delimiter
char *value, line[128];
int i=0;
fp = fopen("test.txt", "r");
if (fp == NULL) {
printf("File doesn't exist\n");
exit(EXIT_FAILURE);
}
while(i < 2 && fgets(line, sizeof(line), fp)){
value = strtok(line, s);
strcpy(result[i][IP], value);
printf("IP : %s\n",result[i][IP]);
value = strtok(NULL, s);
strcpy(result[i][PORT], value);
printf("PORT : %s\n",result[i][PORT]);
i++;
}
puts("");
for (int k=0;k<2;k++){
for (int j=0;j<2;j++){
printf("%s\n",result[k][j]);
}
}
fclose(fp);
return 0;
}
What you are doing wrong is that you are assigning "value" pointer to elements of "result" array. In your implementation, all the elements of "result" just mirror the value of "value" pointer. Therefore, when you change the value of "value", you also change all the "result" elements.
Because of that, you should use strcpy function after allocating memory for the specific "result" element.
value = strtok(str, s);
result[i][0]=malloc(strlen(value) + 1);
strcpy(result[i][0], value);
When you want to keep-copy strings you have to use the function strcpy()
Instead of result[i][x] = value you should do the following
strcpy(result[i][x], value);
Edit: Before the strcpy you have to use malloc to allocate memory for the result[i][x] string.
eg:
result[i][0] = malloc(10 * sizeof(char));
I suggest using malloc for allocating space for each ip and port, and freeing them at the end with free. Additionally, a struct might be handy here, if you have bigger text files in the future that you want to use.
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COLS 2
#define MAXCHAR 10
#define BUFFSIZE 128
void exit_if_null(void *ptr, const char *msg);
int
main(void) {
FILE *filename;
char *result[COLS][MAXCHAR+1];
char buffer[BUFFSIZE];
char *ip, *port;
int row, i = 0;
filename = fopen("ips.txt", "r");
if (filename == NULL) {
fprintf(stderr, "%s\n", "Error reading file!\n");
exit(EXIT_FAILURE);
} else {
while (fgets(buffer, BUFFSIZE, filename) != NULL && i < 2) {
ip = strtok(buffer, "-");
port = strtok(NULL, "\n");
result[i][0] = malloc(strlen(ip)+1);
exit_if_null(result[i][0], "Initial Allocation");
result[i][1] = malloc(strlen(port)+1);
exit_if_null(result[i][1], "Initial Allocation");
strcpy(result[i][0], ip);
strcpy(result[i][1], port);
i++;
}
}
for (row = 0; row < i; row++) {
printf("%s\n", result[row][0]);
printf("%s\n", result[row][1]);
free(result[row][0]);
free(result[row][1]);
result[row][0] = NULL;
result[row][1] = NULL;
}
return 0;
}
void
exit_if_null(void *ptr, const char *msg) {
if (!ptr) {
printf("Unexpected null pointer: %s\n", msg);
exit(EXIT_FAILURE);
}
}
in my program, I provide a directory which contains text files. Each of the text files contain a few hundred lines in the following format
Username,Password,BloodType,Domain,Number
I then create a thread for each file in the directory which will merge-sort(by number) these lines into the array char* text_lines[6000];
I can't figure out why I'm getting a segmentation fault because I'm getting different output on every run.
Heres my code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
void store_line(char* line);
void* my_merge_sort(void* file);
char** text_lines;
int main(int argc, char* argv[])
{
if(argc != 2)
{
fprintf(stderr, "usage: ./coolsort <directory>\n");
}
else
{
text_lines = malloc(6000 * sizeof(char*));
DIR* the_directory;
int filecount = 0;
struct dirent* directory_files[50];
if((the_directory = opendir(argv[1])) != NULL)
{
//make a list of the files in the directory
while((directory_files[filecount++] = readdir(the_directory))) ;
filecount--;
//<<<DEBUGGING INFO>
int i;
fprintf(stderr,"there are %i files in %s:\n", filecount, argv[1]);
for(i = 0; i < filecount; i++)
{
fprintf(stderr, "%s\n",directory_files[i]->d_name);
}
char cwd[512];
chdir(argv[1]);
getcwd(cwd, sizeof(cwd));
fprintf(stderr, "the CWD is: %s\n", cwd);
//<DEBUGGING INFO>>>
//lets start some threads
pthread_t threads[filecount-2];
int x = 0;
for(i = 0; i < (filecount); i++ )
{
if (!strcmp (directory_files[i]->d_name, "."))
continue;
if (!strcmp (directory_files[i]->d_name, ".."))
continue;
pthread_create(&threads[x++], NULL, my_merge_sort, (void*)directory_files[i]->d_name);
}
//do stuff here
//
}
else
{
fprintf(stderr, "Failed to open directory: %s\n", argv[1]);
}
}
}
void* my_merge_sort(void* file)
{
fprintf(stderr, "We got into the function!\n");
FILE* fp = fopen(file, "r");
char* buffer;
char* line;
char delim[2] = "\n";
int numbytes;
//minimize I/O's by reading the entire file into memory;
fseek(fp, 0L, SEEK_END);
numbytes = ftell(fp);
fseek(fp, 0L, SEEK_SET);
buffer = (char*)calloc(numbytes, sizeof(char));
fread(buffer, sizeof(char), numbytes, fp);
fclose(fp);
//now read the buffer by '\n' delimiters
line = strtok(buffer, delim);
fprintf(stderr, "Heres the while loop\n");
while(line != NULL)
{
store_line(line);
line = strtok(buffer, NULL);
}
free(buffer);
}
void store_line(char* line)
{
//extract the ID.no, which is the fifth comma-seperated-token.
char delim[] = ",";
char* buff;
int id;
int i;
strtok(line, delim);
for(i = 0; i < 3; i++)
{
strtok(line, NULL);
}
buff = strtok(line, NULL);
id = atoi(buff);
//copy the line to text_lines[id]
memcpy(text_lines[id], line, strlen(line));
}
edit: I checked to make sure that it would fit into the initial array, and found that the highest ID is only 3000;
You use of strtok() is wrong:
line = strtok(buffer, NULL);
should be
line = strtok(NULL, delim);
Another mistakes should be fixed similarly.
The elements of text_lines are uninitialized:
text_lines = malloc(6000 * sizeof(char*));
this allocated 6000 pointers to char, but none of these pointers are initialized.