I have the following code which works perfectly when not using malloc, but when I want to add in dynamic memory allocation it says segmentation fault although it compiles without warnings or errors. Why?
Thanks in advance
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 30
#define STR 200
#define MAXLEN 40
struct human { //Va
char name[MAXLEN];
char surname[MAXLEN];
int age;
float weight;
};
int main(int argc, char *argv[]) {
char *dlim= ",", *end = "\n", *stop = NULL;
char *tok, *string;
string = (char *)malloc(sizeof(char) * STR);
int i = 0, j = 0;
struct human man[MAXNUM];
FILE *fin = fopen("data.txt", "r");
if (string == NULL) {
printf("Memory not allocated");
}
if (fin == NULL) {
printf("Cannot open file\n");
exit(0);
}
while (fgets(string, sizeof(string), fin)) {
tok = strtok(string, dlim);
strcpy(man[i].name, tok);
tok = strtok(stop, dlim);
strcpy(man[i].surname,tok);
tok = strtok(stop, dlim);
man[i].age = atoi(tok);
tok = strtok(stop, dlim);
man[i].weight = atof(tok);
i++;
}
fclose(fin);
free(string);
j = i;
i = 0;
while (i < j) {
printf("%s %s %d %f \n", man[i].name, man[i].surname, man[i].age, man[i].weight);
i++;
}
return 0;
}
When you make string an allocated array of char, sizeof(string) no longer gives you the size of the array, it gives you the size of the pointer. Therefore you must change the loop to tell fgets the size of your array:
while (fgets(string, STR, fin)) {
...
Or better, if you reallocate the array to size size:
while (fgets(string, size, fin)) {
...
Related
This question already has answers here:
How can I allocate memory and return it (via a pointer-parameter) to the calling function?
(11 answers)
C - Changing the value of a variable outside of a function by passing pointers
(4 answers)
Closed 5 months ago.
Hello just looking to implement a function that initializes an array of char pointers in the string_split function bellow. wondering how to properly do this currently getting a segmentation fault. The segmentation fault occurs when i try to print the tokens in the main function. I may be approaching this the wrong way if so please point me in the right direction.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
uint32_t string_split(char **tokens, char *buffer,uint32_t len, char del);
uint32_t character_count(char * str, char c);
int main (int argc, char *argv[])
{
uint32_t i,len;
char * buffer = 0;
long length;
FILE * f;
char **tokens = NULL;
if (argc < 2)
{
printf("usage: %s <config_file>\n\r" , argv[0]);
return 0;
}
f = fopen(argv[1], "rb");
if (f)
{
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(length + 1);
if (buffer)
{
fread(buffer, 1, length, f);
buffer[length] = '\0';
}
fclose(f);
}
if (buffer)
{
//printf("%s", buffer);
len = string_split(tokens, buffer, strlen(buffer), '\n');
printf("len:%d\n\r", len);
for(i = 0; i < len; i++)
{
printf("%s\n\r", tokens[i]);
}
// start to process your data / extract strings here...
}
return 0;
}
uint32_t string_split(char **tokens, char *buffer,uint32_t len, char del)
{
uint32_t i, size, cnt;
char *token = NULL;
cnt = 0;
size = character_count(buffer,del);
//printf("size:%d\n\r", size);
tokens = malloc(size* sizeof(char *));
for(i=0; i < size; i++)
{
tokens[i] = NULL;
}
token = strtok(buffer, &del);
tokens[cnt] = token;
cnt++;
while( token != NULL ) {
//printf( " %s\n", token ); //printing each token
token = strtok(NULL, &del);
if (token != NULL)
{
tokens[cnt] = token;
cnt++;
}
}
return cnt;
}
uint32_t character_count(char * str, char c)
{
uint32_t i,cnt;
cnt = 0;
for(i=0; i < strlen(str); i++)
{
if (str[i] == c)
cnt++;
}
return cnt;
}
I realize this question has been asked often but I still dont really understand how it works. I want to try and read my file into my structures, inside a function and pass the structures through pointers to the function. I am unsure about how to even write the function prototype.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 90
#define STR 200
#define MAXLEN 40
struct human {
char name[MAXLEN];
char surname[MAXLEN];
int age;
float weight;
};
int main(int argc, char *argv[]) {
char *dlim= " ", *end = "\n";
char *string;
string = (char *)malloc(sizeof(char) * STR);
int i = 0, j = 0;
struct human *man = malloc(sizeof(struct human) * MAX);
FILE *fin = fopen("data.txt", "r");
if (fin == NULL) {
printf("Cannot open file\n");
exit(0);
}
while (fgets (string, STR, fin)){
read (string, &man[i], dlim, end);
i++;
}
fclose(fin);
free(string);
free(man);
return 0;
}
struct human *man read(char *fstring, struct *man, char *div, char *end){
int i=0;
char *tok;
tok = strtok(string, dlim);
strcpy(man[i].name, tok);
tok = strtok(NULL, dlim);
strcpy(man[i].surname,tok);
tok = strtok(NULL, dlim);
man[i].age = atoi(tok);
tok = strtok(NULL, end);
man[i].weight = atof(tok);
return man[i];
}
Whats the function meant to look like? And am i correct in assuming that through the use of pointers, the struct will be automatically be updated in main, without needing to return something in the function?
Can the function also return nothing (void), because the use of pointers will automatically pass onto main?
Thank you!
Your code is close but the pointer logic in the subroutine that fills in the human structure is incorrect. See if the following rework, and slight simplification, helps you understand how to pass the structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXIMUM_HUMANS 90
#define MAXIMUM_INPUT_STRING_LENGTH 200
#define MAXIMUM_STRING_LENGTH 40
struct human {
char name[MAXIMUM_STRING_LENGTH];
char surname[MAXIMUM_STRING_LENGTH];
int age;
float weight;
};
void initialize_human(char *string, struct human *man, char *delimiter, char *end) {
char *token;
token = strtok(string, delimiter);
strcpy(man->name, token);
token = strtok(NULL, delimiter);
strcpy(man->surname, token);
token = strtok(NULL, delimiter);
man->age = atoi(token);
token = strtok(NULL, end);
man->weight = atof(token);
}
int main(int argc, char *argv[]) {
char *dlim= " ", *end = "\n";
char string[MAXIMUM_INPUT_STRING_LENGTH];
struct human humans[MAXIMUM_HUMANS];
FILE *fin = fopen("data.txt", "r");
if (fin == NULL) {
fprintf(stderr, "Cannot open file\n");
exit(1);
}
int population; // after loop, this contains total body count
for (population = 0; fgets(string, MAXIMUM_INPUT_STRING_LENGTH, fin); population ++) {
initialize_human(string, &humans[population], dlim, end);
}
printf("population: %d\n", population);
printf("last added: %s who weighs %f\n", humans[population - 1].surname, humans[population - 1].weight); // test if we loaded it up correctly
fclose(fin);
return 0;
}
I am getting a segmentation fault error. When I comment out "wordlength = strlen(token);" it runs fine. I don't know why it the seg fault happens when I assign a strlen(token) just fine to an int a few lines before this one. I would appreciate any help possible.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define char_max 60
int main(int argc, char *argv[])
{
FILE *fp = fopen(argv[2],"r");
char **wordlist;
int row = 1;
int i;
char temp[100];
char *token;
int wordlength;
int lengthcounter;
wordlist = (char**)malloc(row*sizeof(char*));
for(i = 0; i < row; i++)
{
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
}
while(fgets(temp, sizeof(temp), fp) != NULL)
{
lengthcounter = 0;
wordlength = 0;
token = strtok(temp, " ");
strcat(wordlist[row-1], token);
printf("%s\n", wordlist[row-1]);
lengthcounter = strlen(token);
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
printf("The lengthcounter is %d\n", lengthcounter);
}
free(wordlist);
fclose(fp);
return 0;
}
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
What happens in the last iteration of the loop when token is NULL? You pass it to strlen anyway.
Also, this is almost certainly wrong:
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
You're allocating space for pointers, not characters. So why sizeof(char*)? Also, don't cast the return value of malloc. This is C, not C++.
I tried really hard to search for a solution to this but I can't think of good enough keywords.
Currently I'm having troubles grasping the concept behind makeargv and it's usage with triple pointers (I have no idea what ***foo means, it doesn't seem to be as easy of a concept as **foo or *foo). So I made my own:
const char **makeargv(char *string, int *numargs) {
string = string + strspn(string, delims);
char *copy = malloc(strlen(string) + 1);
int i;
strcpy(copy, string);
int numtokens;
if (strtok(copy, delims) != NULL) {
for (numtokens = 1; strtok(NULL, delims) != NULL; numtokens++) {}
}
strcpy(copy, string);
const char *results[numtokens+1];
results[0] = strtok(copy, delims);
for (i = 1; i < numtokens; i++) {
results[i] = strtok(NULL, delims);
}
results[numtokens+1] = NULL;
*numargs = numtokens;
return results;
}
Here's the part at where it breaks:
void parse_file(char* filename) {
char* line = malloc(160*sizeof(char));
FILE* fp = file_open(filename);
int i = 0;
int numargs = 0;
int *pointer = &numargs;
while((line = file_getline(line, fp)) != NULL) {
if (strlen(line) == 1){
continue;
}
const char **args = makeargv(line, pointer);
printf("%s\n", args[0]);
printf("%s\n", args[1]);
/* This prints out args[0], but then args[1] causes a seg fault. Even if I replace
the args[1] with another args[0] it still causes a seg fault */
}
fclose(fp);
free(line);
}
I have a working array of strings. However when I try to print out the strings in the array, I can only print 1 of my choice and then it seg faults for any subsequent calls. lets pretend my array of strings is argv[3] = {"Yes", "no", "maybe"}, if i call argv[0], it will let me call "Yes", but any other calls (even if i call argv[0] again) do not work and cause a segfault. I can call any of the elements in the array, but once i call one the rest cease to work causing segfaults.
Help please? D: This is in C.
const char *results[numtokens+1];
This array "results" is a local variable, it is only available inside of "makeargv".
You'd better use malloc:
results = malloc(numtokens+1)
And I believe there is memory leak in your code.
You will not be able to free the memory for "char *copy"
char *copy = malloc(strlen(string) + 1);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **makeargv(char *string, int *numargs) {
static const char *delims = " \t\n";
string = string + strspn(string, delims);
char *copy = malloc(strlen(string) + 1), *p = copy;
strcpy(copy, string);
int numtokens;
for (numtokens = 0; strtok(p, delims); ++numtokens, p = NULL);
char **results = malloc(sizeof(char*)*(numtokens+1));
strcpy(copy, string);
int i;
p = copy;
for (i = 0; i < numtokens; ++i, p = NULL)
results[i] = strtok(p, delims);
results[i] = NULL;
*numargs = numtokens;
return results;
}
FILE *file_open(char *filename){
FILE *fp = fopen(filename, "r");
if(!fp){
perror("file_open");
exit(1);
}
return fp;
}
void parse_file(char* filename) {
char* line = malloc(160*sizeof(char));
FILE* fp = file_open(filename);
int i = 0, numargs = 0;
while(fgets(line, 160, fp)){
if (*line == '\n')
continue;
char **args = makeargv(line, &numargs);
for(i = 0;i<numargs;++i)
printf("%s\n", args[i]);
printf("\n");
if(args[0])
free(args[0]);
free(args);
}
fclose(fp);
free(line);
}
int main(int argc, char *argv[]){
parse_file(argv[1]);
return 0;
}
I am writing a program to read info from a text file and I had everything working. The problem is that I am trying to add the functionality to calculate the mean of some of fields and have to convert the strings to doubles. I noticed that atof would work in some cases but would return -1 for the most part. i then realized that I didn't include stdlib, so I added that, but now I am getting a segmentation fault with just that one change.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
main(int argc, char *argv[]){
int numParts=10;
long numTests=49000;
char filename[] = "sweep_data.txt";
FILE *fp= fopen(filename,"r");
FILE *out= fopen("TesterData.csv", "w+");
FILE *meanf= fopen("meanData.txt", "w+");
char delims[] = " <>";
char *result = NULL;
char line [128];
char *TestNum=NULL;
char *TestName=NULL;
char *TestName2=NULL;
char *SequencerName=NULL;
char *lowlim=NULL;
char *hilim=NULL;
char *value=NULL;
char *units=NULL;
char *DeviceNum=NULL;
char ValueArray[numTests][10];
char ***ValuePtr = NULL;
char InfoArray[numTests][20];
char ***InfoPtr = NULL;
double mean[numTests];
long sum;
int intResult;
int count=0;
int DeviceCount=-1;
int i,j, m,n,k,a,b, len, mLen;
/*Allocate Memory for 2D arrays*/
ValuePtr = malloc(numParts * sizeof *ValuePtr);
for(i=0; i<numParts;i++){
ValuePtr[i]=malloc(numTests*sizeof *ValuePtr);
for(j=0; j<numTests; j++){
ValuePtr[i][j] = malloc(strlen(ValueArray[j]) +1);
}
}
InfoPtr = malloc(6 * sizeof *InfoPtr);
if(InfoPtr != NULL){
for(a=0; a<6;a++){
InfoPtr[a]=malloc(numTests*sizeof *InfoPtr);
for(b=0; b<numTests; b++){
InfoPtr[a][b]= malloc(strlen(InfoArray[b]) +1);
}
}
}
while(fgets(line, sizeof line, fp) != NULL){
result = strtok(line, delims);
TestNum=result;
intResult = strtol(result, NULL, 10);
if(intResult ==0){
if(strcmp(result, "Device:")==0){
DeviceCount++;
count=0;
}
continue; //if doesn't start with a number go to next line
}
result = strtok(NULL, delims);
TestName= result;
result = strtok(NULL, delims);
TestName2= result;
result = strtok(NULL, delims);
SequencerName = result;
lowlim=SequencerName;
if(atof(SequencerName)>1 || atof(SequencerName)<-1){
result= strtok(NULL, delims);
lowlim=result;
strcat(TestName, TestName2);
}
else
SequencerName= TestName2;
if(strstr(TestName, "%")!=NULL || strcmp(TestName,"PTgen")==0 || strcmp(TestName,"mode")==0){
units="NA";
}
else if(strstr(TestName, "2nd") == NULL && strstr(TestName, "3rd") == NULL){
result= strtok(NULL, delims);
units = result;
}
result= strtok(NULL, delims);
value=result;
if(strstr(TestName, "%")==NULL && strcmp(TestName,"PTgen")!=0 && strcmp(TestName,"mode")!=0){
result=strtok(NULL, delims);
if(strstr(TestName, "2nd") != NULL || strstr(TestName, "3rd") != NULL)
units = result;
}
result=strtok(NULL, delims);
hilim=result;
if(hilim[strlen(hilim)-1]=='\n'){
hilim[strlen(hilim)-1]='\0';
hilim[strlen(hilim)-1]='\0';
}
if(DeviceCount==0){
strcpy(InfoPtr[0][count], TestNum);
strcpy(InfoPtr[1][count], TestName);
strcpy(InfoPtr[2][count], SequencerName);
strcpy(InfoPtr[3][count], lowlim);
strcpy(InfoPtr[4][count], hilim);
strcpy(InfoPtr[5][count], units);
}
strcpy(ValuePtr[DeviceCount][count],value);
count++;
}
for(b=0;b<numTests;b++){
sum=0;
for(a=0;a<numParts;a++){
fprintf(meanf, "%s\n", ValuePtr[a][b]);
sum=atof(ValuePtr[a][b]);
fprintf(meanf, "%f\n",sum);
}
mean[b]=sum/numParts;
for(n=0; n<2;n++){
fprintf(meanf, "%s ", InfoPtr[n][b]);
}
fprintf(meanf, "%f\n",mean[b]);
}
printf("NumTests: %i\n",count); //number of tests run
printf("NumParts: %i\n", DeviceCount+1);//number of parts run
fprintf(out,"Test#, TestName,SeqName,LowLim,UpLim,Units,");
for(j=1; j<=numParts;j++){
fprintf(out," Device#%i,", j);
}
fprintf(out, "\n");
for (n = 0; n < numTests; n++) {
for(a=0;a<6;a++){
fprintf(out, "%s", InfoPtr[a][n]);
fprintf(out, ", ");
}
for (m =0; m < numParts ; m++) {
fprintf(out, "%s, ", ValuePtr[m][n]);
}
fprintf(out, "\n");
}
}
The part where I was needing to convert to a double is
for(b=0;b<numTests;b++){
sum=0;
for(a=0;a<numParts;a++){
fprintf(meanf, "%s\n", ValuePtr[a][b]);
sum+=atof(ValuePtr[a][b]);
fprintf(meanf, "%f\n",sum);
}
mean[b]=sum/numTests;
for(n=0; n<2;n++){
fprintf(meanf, "%s ", InfoPtr[n][b]);
}
fprintf(meanf, "%f\n",mean[b]);
}
The following line doesn't seem correct. It is using strlen on something that has not been initialized. So the results would be nondeterministic:
ValuePtr[i][j] = malloc(strlen(ValueArray[j]) +1);
The use of that later in the calls to atof() would quite possibly not produce consistent results. And depending on the actual allocation size, it could result in a seg fault when storing data in it.
Not that this has anything to do with the segfault, but:
ValuePtr = malloc(numParts * sizeof **ValuePtr);
...
InfoPtr = malloc(6 * sizeof **InfoPtr);