String arrays in C segmentation fault - c

I'm trying to create an array of strings and pass strings to this array.
struct node {
int vertex_no;
};
int main() {
char city1[100], city2[100], buffer[999];
int distance;
FILE *fp;
fp = fopen("cities.txt", "r+");
if(fp == NULL)
perror("Error");
//Change - characters with space
while(1) {
char ch = fgetc(fp);
if(ch == '-') {
fseek(fp, ftell(fp)-1, SEEK_SET);
fputc(' ', fp);
}
if(ch == EOF)
break;
}
//Get to beginning of the file
fseek(fp, 0, SEEK_SET);
//Pass first line
fgets(buffer, sizeof(buffer), fp);
int i, j, v = 0;
char cities[100][100];
for(i = 0; i < 100; i++)
for(j = 0; j < 100; j++)
cities[i][j] = '\n';
int vertices = 0;
int add = 1;
//Find how many vertices we have
while(fscanf(fp, "%s %s %d", city1, city2, &distance) == 3) {
if(cities[0][0] == '\n') {
strcpy(cities[0], city1);
strcpy(cities[1], city2);
v = 2;
}
for(i = 0; cities[i][0] != '\n'; i++) {
//Search city1 inside cities array
if( strcmp(cities[i], city1) == 0 ) {
add = 0;
break;
}
//If not found add it to array
if(add) {
strcpy(cities[v], city1);
v++;
}
//Same search for city2
add = 1;
if( strcmp(cities[i], city2) == 0 ) {
add = 0;
break;
}
//If not found add it to array
if(add) {
strcpy(cities[v], city2);
v++;
}
}
}
for(i=0;cities[i][0] != '\n';i++)
printf("City no.%d = %s\n", i, cities[i]);
printf("Last city1, city2 and distance: %s, %s, %d", city1, city2, distance);
return 0;
}
As a result I get
segmentation fault(core dumped)
When I try to do something like this
char *test = NULL;
strcpy(test, "hello");
return 0;
I get the same segmentation fault again. Although when allocate space like this:
char *test = (char *) malloc(100);
There is no problem. But when I do like this:
char test[100];
There is also no problem. So that's why I don't understand the reason of getting segmentation fault even tho I used
char strings[100][100];
instead of
char *strings[100];

Following allocates a single pointer and sets that pointer to point to a single array of 100 characters. I.E. no place to insert 100 city strings.
char *test = NULL;
strcpy(test, "hello");
return 0;
....
char *test = (char *) malloc(100);
....
Following declares an array of 100 bytes with no room for 100 city strings
char test[100];
Following declares an array of 100 character arrays, of which each array is 100 bytes long
char strings[100][100];
Following declares an array of 100 pointers to char, not 100 character strings. So you would need to 'malloc' room for each city string and insert that pointer into the appropriate offset into the array.
char *strings[100];

Related

Function returning different values inside another function

My first function checks for the number of letters that a substring contains from its string.
int num_matches(char* word, char* letters) {
char scrabble[128];
strcpy(scrabble, letters);
int num = 0;
for (int i = 0; i < strlen(word); i++) {
if (strchr(letters, word[i]) == NULL) {
return -1;
}
for (int j = 0; j < strlen(letters); j++) {
if (word[i] == letters[j]) {
num++;
scrabble[j] = '\0';
break;
}
}
}
return num;
}
It returns 4 for "QWOP", "QWOP". However, inside the following function it is returning the same incorrect value for every function call, even when buff and letters print as "QWOP", "QWOP" from my debugging attempt.
void read_words(int num_count[128], char* (*word_idx)[128], int argc, char** argv) {
FILE* fp = fopen(argv[1], "r");
char* letters = argv[2];
int idx = 0;
char buff[128];
int result = 0;
while (fgets(buff, 128, fp) != NULL) {
printf("buff:%s letters:%s\n", buff, letters);
result = num_matches(buff, letters);
printf("result: %d\n", result);
num_count[idx] = result;
char* word = malloc(strlen(buff) + 1);
strcpy(word, buff);
(*word_idx)[idx] = word;
idx++;
result = 0;
}
fclose(fp);
}
buff:QWOP
letters:QWOP
result: -1
My txt file:
ABC
DEFG
QWOP
QWOP
QUOKKA
QUOLL
QUASH
QUANDONG
Since fgets stops at a newline and there are no spaces in my text file, I don't think there should be any problems with reading buff.
fgets reads the data with \n character at the end.
Your function will fail in this case. It is very easy to test:
int main(void)
{
printf("%d\n", num_matches("ABCD", "ABCD"));
printf("%d\n", num_matches("ABCD\n", "ABCD"));
}
Result:
4
-1
You need to remove \n from the buff.
Another problem is the second function. The parameter char* (*word_idx)[128] is a pointer to an array of 128 pointers to char. I do not think that is something you want.

C programming: Check that each character is a valid number between 0 and 9, ignoring formatting characters

I am a beginner at coding and am currently in a course for this. I have been asked to produce a program that has a special function to convert the timestamps in a file into something that can be sorted from earliest to latest based on a numerical value. These would be imported from a file into an array. Some points of the assignment are:
The array of strings should be allocated dynamically to minimise the amount of memory used.
Create a function called timeStampToSeconds() that converts a timestamp string to a long int, which represents the number of seconds elapsed since 01/01/2000 00:00:00.
Your code will need to check that each character is a valid number between 0 and 9, ignoring formatting characters ('/', ' ', ':', '-') and convert the characters to their equivalent integers before being used to calculate the number of seconds elapsed since the above starting point.
I have included my code but am wondering if anyone has any pointers to help me on point 2 & 3? I have started with trying to implement point 3 with the strtok function, but I think I may be way off on this.Curently my function prototype is not doing what I had hoped for this.
Any advice would be much appreciated.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 50
void timeStampToSeconds(char array[]);
int main(void)
{
char array[50][20];
char input[10], filename[] = "Timestamps", outputfile[40], file_ext[4] = ".dat";
int i = 0, n = 0, j, x = 0, y = 0, o = 0;
double datetime = 0;
while (*input != *filename) {
printf("\nPlease enter the names of the required Input file: \n");
scanf("%s", input);
if (*input == *filename) {
printf("Input accepted!\n");
}
else printf("File name not found.Please try again!\n");
}
printf("Please enter the name of the sorted Output file to be created: \n");
scanf("%s", &outputfile);
strncat(&outputfile, &file_ext, 4); /*appends file extension characters to outputfile
variable characters*/
FILE* Ptr = NULL;
FILE* cfPtr = (char*)malloc(100 * sizeof(char));
if ((cfPtr = fopen("Timestamps.dat", "r")) == NULL) {
printf("File could not be opened\n");
}
while (!feof(cfPtr))
{
for (i = 0; i < 50; ++i)
{
for (j = 0; j < 20; ++j)
{
array[x][j] = fgetc(cfPtr);
y++;
}
x++;
}
}
fclose(cfPtr);
timeStampToSeconds(array);
if ((Ptr = fopen(outputfile, "w")) == NULL) {
printf("File could not be opened\n");
}
fwrite(array, sizeof(char), sizeof(array), Ptr);
fclose(Ptr);
return 0;
}
void timeStampToSeconds(char array[])
{
array;
long int n = 0, j = 0;
const char a[2] = "/"; const char b[2] = "-";
const char c[2] = ":";
char* token; char* token2; char *token3;
for (int i = 0; i < SIZE - 1; ++i) {
token = strtok(array, a);
while (token != NULL) {
token = strtok(NULL, a);
}
token2 = strtok(token, b);
while (token2 != NULL) {
token2 = strtok(NULL, b);
}
token3 = strtok(token2, c);
while (token3 != NULL) {
token3 = strtok(NULL, c);
}
token3 = array;
}
for (int i = 0; i < SIZE - 1; ++i) {
n = atol(array[i]);
array[i] = n;
}
}

I have a csv file and I want to put data into a struct, but I don't know why it retain only the last line

Why is the struct retain only the last line of the file?
typedef struct Student
{
char* nume;
char* prenume;
int cod;
float nota;
}Student;
int fileNrLines(int lines)
{
FILE *fp = fopen("students.csv", "r");
char ch;
lines = 0;
lines++;
while ((ch = fgetc(fp)) != EOF)
{
if (ch == '\n')
lines++;
}
fclose(fp);
return lines;
}
void printStudents(Student *myStudents, int size)
{
for (int i = 0; i < size; ++i)
printf("| %20s | %20s | %d | %.2f |\n",
myStudents[i].nume, myStudents[i].prenume, myStudents[i].cod, myStudents[i].nota);
}
void main()
{
int lines=0;
Student *myStudents;
myStudents = (Student*)malloc(fileNrLines(lines) * sizeof(Student));
lines = fileNrLines(lines);
FILE *fp = fopen("students.csv", "r");
char myLine[50];
char* myWord;
int index = 0;
for (int i = 0; i < lines; i++)
{
fgets(myLine, 50, fp);
int contor = 1;
myWord = strtok(myLine, ",");
while (myWord!=NULL)
{
myStudents[index].nume = myWord;
//puts(myStudents[i].nume);
myWord=strtok(NULL, ",");
contor++;
myStudents[index].prenume = myWord;
//puts(myStudents[i].prenume);
myWord=strtok(NULL, ",");
contor++;
int x = atoi(myWord);
myStudents[index].cod = x;
//printf(" %d \n",myStudents[i].cod);
myWord=strtok(NULL, ",");
contor++;
float y = atoll(myWord);
myStudents[index].nota = y;
//printf(" %.2f \n", myStudents[i].nota);
myWord=strtok(NULL, ",");
contor++;
}
index++;
}
fclose(fp);
printStudents(myStudents, &lines);
}
if I print into the while loop is ok but after that not
The problem is that (for example this line)
myStudents[index].nume = myWord;
doesn't populate nume with a new and unique string. Instead, it's simply assigning the memory location that myWord is currently pointing to. Since this is the first token on each line, it'll always likely be pointing to the start of myLine so each nume will be identical. For other columns, the position of myWord will be different so you'll get rather more unexpected results.
Instead you want to create a new string each time, like this.
myStudents[index].nume = strdup(myWord);
Or
myStudents[index].nume = malloc(strlen(myWord)+1);
strcpy(myStudents[index].nume,myWord);
You will need to remember to free() this memory that has been allocated.

segmentation fault after a new line

I'm running in to a segmentation fault on the line enclosed with **.
I pipe this output:
|status: OK|
|version: 0.85|
|author: PBrooks|
|nitems: 0|
in to my code below and it gives me a segmentation fault after I print out the '\n' in my printf statement. I don't know how to debug this though.. Does anyone have a clue?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char string[300];
struct NameValue {
char *name;
char *value;
};
struct NameValue *pairs;
void ReadStdin(int argc, char *argv) {
int x;
fread(string, sizeof (char), 300, stdin);
printf("%s\n", string);
}
void ParseInput() {
int x, num = 0; //figure out how many i need
for (x = 0; x < 300; x++) {
if (string[x] == '|') {
num++;
}
}
num /= 2; //num = how many i need
pairs = (malloc(num)); //allocate the array
int pipe = 0, i, j = 0, tempCounter = 0;
char tempName[50], tempValue[50];
printf("%lu \n", sizeof (string) / sizeof (string[0]));
if (pairs != 0) {
for (i = 0; i <= num; i++) { //counts pairs
printf("i = %i\n", i);
printf("j = %i, pipe: %i \n", j, pipe);
if (string[j] == '|') {
printf("there's a pipe\n");
pipe++;
j++;
}
while (string[j] != ':') {
printf("counter for main string: %i\n tempCounter: %i\n", j, tempCounter);
tempName[tempCounter] = string[j];
tempCounter++;
j++;
if (string[j] == ':') {
tempName[tempCounter] = '\0';
tempCounter = 0;
**printf("~~~~tempName\n is: %s", tempName);**
break;
}
}
while (string[j] != '|') {
j++;
tempValue[tempCounter] = string[j];
tempCounter++;
if (string[j] == '|') {
tempValue[tempCounter] = '\0';
tempCounter = 0;
strcpy(pairs[i].value, tempValue);
pipe++;
break;
}
}
}
}
}
int main(int argc, char *argv) {
ReadStdin(argc, argv);
ParseInput();
return (EXIT_SUCCESS);
}
edit: Sorry! I removed the null terminate character line by accident. It is in there but it's still giving me the error.
edit: a bit more information: The j variable gets incremented up to 6 and and the temp counter gets incremented up to 5 before the program spits out a segmentation fault.
You never null terminate the string tempName. Then you try printing it here:
if (string[j] == ':') {
tempCounter = 0;
**printf("~~~~tempName\n is: %s", tempName);**
break;
}
Strings in C are a series of characters in memory, terminated by a null byte (i.e. '\0'). You're copying bytes into a buffer, but you never yourself create this null terminator, hence printf runs off the end and into undefined memory.
Instead, at the end of the while loop, you need to assign the next character in tempName to '\0', probably inside the while loop just before printing it.
Before tempCounter = 0, just put tempName[tempCounter] = '\0';.
I figured it out. Not only did I need to malloc the pairs but I also need to malloc the member variables inside each malloc's pairs.
I ended up using my tempCounter to see how many characters I needed and malloc'd the correct amount for the member variables.

How can i use input data from a file in C programming?

I have a program that uses word search. I have a data file which contains the puzzle and the words. What can i implement into my program so that it reads the file and stores the letters present in it as an array?
Example of the data file (it is called testdata):
h e l l o a c d
f g b w o r l d
h a c c v b n a
e q b x n t q q
y e h n c a q r
hello
world
hey
I want to store all the letters in a 2-d array.
Also, I need to store all the words in a 1-dimensional array.
The maximum number of rows of columns or rows that AxA square of letters that is possible in a data file is 25. So, I believe that I should declare an array of that size for the letter and then write them into that array.
I just can't figure out how to read them into that array. There is a space after each letter in the array and no spaces in the words so I think that might be helpful when putting the letters in one array and words in another.
Given your question, and your input, there are a few questions, but in the interest of time, for now, I have made some assumptions about the dimensions of the array, i.e. that it is not necessarily square (as implied by columns or rows that AxA square). The actual data sample disagrees, so I wrote a routine that counts everything as it goes. The letter array is simply an array of arrays, but since it is stored in sequential memory, it just looks like one long array. The strings are each in there own location as well. In any case, this code should illustrate enough to get you on the right track...
#include <ansi_c.h>
#include <stdio.h>
void GetFileContents(char *file, int *nWords, int *lw, int *r, int *c);
void allocMemoryStr(int numStrings, int max);
void allocMemoryLtr(int numStrings, int max);
void freeMemoryStr(int numStrings);
void freeMemoryLtr(int numletters);
#define FILENAME "c:\\dev\\play\\_puzzle.txt"
char **letters;
char **strings;
int main()
{
int longest, cnt, wCount, rows, cols, i;
char line[260];
FILE *fp;
char *buf=0;
GetFileContents(FILENAME, &wCount, &longest, &rows, &cols);
allocMemoryStr(wCount, longest); //for strings
allocMemoryLtr(rows*cols, 1); //for strings
//read file into string arrays
fp = fopen(FILENAME, "r");
cnt=0;
for(i=0;i<rows;i++)
{
fgets(line, 260, fp);
buf = strtok(line, " \n");
while(buf)
{
strcpy(letters[cnt], buf);
buf = strtok(NULL, " \n");
cnt++; //use as accurate count of words.
}
}
cnt=0;
while(fgets(line, 260, fp)) //get remainder of lines into strings
{
//[EDIT]removed fgets()
buf = strtok(line, " \n");
while(buf)
{
strcpy(strings[cnt], buf);
buf = strtok(NULL, " \n");
cnt++; //use as accurate count of words.
}
}
fclose(fp);
freeMemoryStr(wCount);
freeMemoryLtr(rows*cols);
return 0;
}
void GetFileContents(char *file, int *nWords, int *lw, int *r, int *c)
{
char line[260];
FILE *fp;
char *buf=0;
char temp[80];
int wc=0, rc=0, cc=0, ck=0;
fp = fopen(FILENAME, "r");
while(fgets(line, 260, fp))
{
rc++;
buf = strtok(line, " \n");
while(buf)
{
strcpy(temp, buf); // word handler
if(strlen(temp) > 1)
{
wc++;
rc--; //
}
else if(strlen(temp) == 1) //leter handler
{
cc++;
(cc>ck)?(ck=cc):(cc=cc);
}
buf = strtok(NULL, " \n");
}
cc = 0;
}
fclose(fp);
*nWords = wc;
*r = rc;
*c = ck;
}
void allocMemoryStr(int numStrings, int max)
{
int i;
strings = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
strings[i] = calloc(sizeof(char)*max + 1, sizeof(char));
}
}
void allocMemoryLtr(int numletters, int max)
{
int i;
letters = calloc(sizeof(char*)*(numletters+1), sizeof(char*));
for(i=0;i<numletters; i++)
{
letters[i] = calloc(sizeof(char)*max + 1, sizeof(char));
}
}
void freeMemoryStr(int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(strings[i]) free(strings[i]);
free(strings);
}
void freeMemoryLtr(int numletters)
{
int i;
for(i=0;i<numletters; i++)
if(letters[i]) free(letters[i]);
free(letters);
}
I would parse the file line by line and char by char looking for what i need. In the example (which is untested), i hold three counters to help filling the arrays correctly.
char letters[25][25];
char words[10][25]
int letters_x_pos = 0; // Row counter
int letters_y_pos = 0; // Column counter
int words_pos = 0;
for (int i = 0; i < 25; i++) {
for (int j = 0; j < 25; j++) {
letters[i][j] = '\0';
}
}
const char *line;
while (line = some_read_function()) {
if (!(strlen(line) > 1)) {
continue;
}
if (line[1] == ' ') {
// Line contains letters
const char *letter = line;
while (*letter != '\0') {
if (*letter == ' ' || *letter == '\n' || *letter == '\r') {
continue;
}
else {
letters[letters_x_pos][letters_y_pos++] = *letter;
}
if (letters_y_pos == 25) {
// Maximum reached
break;
}
letter++;
}
// Increment row counter and reset column counter
letters_x_pos++;
letters_y_pos = 0;
if (letters_x_pos == 25) {
// Maximum reached
break;
}
}
else {
// Line contains word
strncpy(words[words_pos++], line, 25);
if (words_pos == 25) {
// Maximum reached
break;
}
}
}

Resources