Storing a char in an array segfault - c

I'm getting a segfault in my code and I'm not sure why. I read through a file and count the number of lines in order to dynamically allocate my arrays. I then rewind the file, read the data in the file, storing the data into variables, and then storing the read variables into arrays, but I'm having trouble with chars.
...
char *aname = malloc(sizeof(char) * 3);
...
// get # lines in file (count)
...
char *aname_seen = malloc(count * (sizeof(char) * 3));
...
rewind(file);
while (fgets(buff, sizeof buff, file) != NULL)
{
if (sscanf(buff, "%s %d %s %s %d %lf %lf %lf %lf %lf\n",
atm, &serial, aname, resName, &resSeq, &x, &y, &z,
&occupancy, &tempFactor) == 10)
{
aname_seen[i] = *aname;
printf("%d: %s vs %s\n", i, aname, aname_seen[i]);
i++;
} // end sscanf if-loop
} // end while loop
I can print aname with printf("%d: %s\n", i, aname) and get the expected output, but I'm getting Segmentation fault (core dumped) when I try printf("%d: %s vs %s\n", i, aname, aname_seen[i]).
This while loop + nested if loop is the same convention I use to count the number of lines, so i will increment up to count. Am I incorrectly allocating aname_seen and not actually giving it count number of char*3 elements? I'm not well versed in messing with char's. More of a numerical fortran buff, so I need some direction.
Thanks in advance!

The %s format specifier is supposed to correspond to a char * argument. In your case, aname_seen[i] is a char, which gets promoted to an int for the purpose of passing to a variadic function (printf). An int is not a char *.
Perhaps you meant one of these:
printf("%d: %s vs %c\n", i, aname, aname_seen[i]);
printf("%d: %s vs %s\n", i, aname, &aname_seen[i]);
If neither of these solve your problem, please explain precisely the behaviour you expect from this expression and give us a minimal, compilable testcase. Your current testcase isn't compilable.

you way you defined aname_seen is a pointer to a char array
char *aname_seen = malloc(count * (sizeof(char) * 3));
so aname_seen[i] is a char
so the
printf("%d: %s vs %s\n", i, aname, aname_seen[i]);
should be
printf("%d: %s vs %c\n", i, aname, aname_seen[i]);

Related

Question about reading int and String from array

I have two-dimensional arrays which contain the input from a file. I want to assign integers and strings from the array to different variables; the integer is set correctly, but the string is not working.
the input is like:
(1,2) apple 2 3 north
but all these information are inside:
char data[MAX_LINES][MAX_LEN];
I am trying to use sscanf to assign values:
sscanf(data[i],"(%d,%d) %8s %d %d %8s",&x,&y,type,&age,&hun,direction);
Code structure by ignoring unrelated code
FILE *in_file = fopen(fileName,"r");
char data[MAX_LINES][MAX_LEN];
int x,y,age,hun;
char type[10];
char deriction[20];
if(! in_file){
printf("cannot read file\n");
exit(1);
}
int line=0;
while(!feof(in_file) && !ferror(in_file)){
if(fgets(data[line],MAX_LEN,in_file) !=NULL ){
char *check = strtok(data[line],d);
line++;
}
}
fclose(in_file);
for(int i = 9; i<14;i++){
sscanf(data[i],"(%d,%d) %8s %d %d %8s",&x,&y,type,&age,&hun,deriction);
}
#include <stdio.h>
int main(){
//Data:
char data[1][100] = {"(1,2) apple 2 3 north"};
//Define variables:
int x, y, age, hun;
char type[10], direction[10];
sscanf(data[0], "(%d,%d) %s %d %d %s", &x, &y, type, &age, &hun, direction);
//Check by printing it out:
printf("(%d,%d) %s %d %d %s\n", x, y, type, age, hun, direction);
printf("x: %d\ny: %d\ntype: %s\nage: %d\nhun: %d\ndirection: %s", x, y, type, age, hun, direction);
//Success:
return 0;
}
If this doesn't work, then the problem might be the data in your array, data.
You have the line char *check = strtok(data[line],d);. You've not shown what d is, but unless it is a string with no characters in common with the input line, strtok() just mangled your stored data, zapping whatever is the first character from d with a null byte. That means your sscanf() will fail because it isn't looking at the whole line. If, perchance, you have const char d[] = "\r\n"; or equivalent, this ceases to be relevant, beyond pointing out that you should show enough code to reproduce the problem.

C adding array a word

#include <stdio.h>
int main()
{
char in_name[80];
FILE *in_file;
char word[50];
char word2[50];
char word3[50];
char *strs[]= {"foo ABAA", "bar", "bletch","4"};
strcpy(*strs[4],"wow");
in_file = fopen("test2.txt", "r");
if (in_file == NULL)
printf("Can't open %s for reading.\n", in_file);
else
{
while (fscanf(in_file, "%s %s %s ", word,word2,word3) != EOF)
{
printf("%s ", word);
printf("%s ", word2);
printf("%s\n", word3);
}
fclose(in_file);
}
printf("%s",strs[3]);
int result = atoi(strs[3] );
printf("\n");
printf("%d",result);
return 0;
}
Im new in C.Im trying to add the "woo" string to the strs array.But it gives an error.Im open to any help.My main point is reading line by line a txt file and adding every word to a array like {"what", "a", "nice","day"}
There are a few steps you must take:
To read a potentially unlimited number of words from your file, you must have an array strs that can hold enough words. Let's say 50:
char *strs[50]= 0;
But this is an array of pointers to strings; the pointers still point nowhere. So you must have memory to store the strings read. We will allocate the memory after each word read.
You open the file and start reading. For each word read, you allocate the memory and store it in the strs array. Then you copy the word to the memory you have just allocated:
int i= 0;
while (fscanf(in_file, "%s %s %s ", word,word2,word3) != EOF)
{
strs[i]= malloc(strlen(word )+1; strcpy(strs[i],word ); i++;
strs[i]= malloc(strlen(word2)+1; strcpy(strs[i],word2); i++;
strs[i]= malloc(strlen(word3)+1; strcpy(strs[i],word3); i++;
}
fclose(in_file);
Thats's all...
what you did wrong and needs noticing:
char *strs[]= {"foo ABAA", "bar", "bletch","4"};
Ths is an array that you initialize with the values between { and }. You do not specify the size and the size is taken by counting the number of initializers between the { and }.
You initialize the array with literal strings. These are constants and cannot be modified. So when you do:
strcpy(*strs[4],"wow");
you do 4 things wrong: 1) entry 4 is beyond your array; 2) you dereference a pointer (strs[4] is already a pointer, so no * needed), and even if we forget this last error, you try 3) to overwrite a read-only string, and that is not allowed. And finally, 4) the string you try to copy is much longer than the string that was there, so even if the string was not read-only, you make an error.
while (fscanf(in_file, "%s %s %s ", word,word2,word3) != EOF)
This use of scanf is not really wrong but it is always better to compare the result with the number of items you want to read. 3 here. Also, we still must guard against reading too many words:
while (i<47 && fscanf(in_file, "%s %s %s ", word,word2,word3)==3)

Why can't I read values into simple variables with simple format string using sscanf() in C?

I am trying to parse some simply formatted text and create a simple data structure of text/numeric records using numeric and short string values. I have debugged and located the problem; it's down to sscanf() not reading the values into my variables using a specific format string (other format strings in the program work well). I have created a simple text file to see what's happening.
Code is as follows:
char *idNumber = (char *)malloc(sizeof (char*));
char *partNumber = (char *)malloc(sizeof (char*));
int amountItems = 0;
double unitPrice = 0;
char *line1 = "Govan, Guthrie (N210) AX299 x 6 $149.94";
char *line2 = "Mustaine, Dave (N106) AX350N x 2 $63.98";
char *line3 = "Van Halen, Edward (N1402) AV2814 x 10 $34.90";
sscanf(line1, "%*s, %*s (%s) %s x %d $%lf", idNumber, partNumber,
&amountItems, &unitPrice);
printf("%s, %s, %d, %f\n", idNumber, partNumber, amountItems, unitPrice);
sscanf(line2, "%*s, %*s (%s) %s x %d $%lf", idNumber, partNumber,
&amountItems, &unitPrice);
printf("%s, %s, %d, %lf\n", idNumber, partNumber, amountItems, unitPrice);
sscanf(line3, "%*s, %*s (%s) %s x %d $%lf", idNumber, partNumber,
&amountItems, &unitPrice);
printf("%s, %s, %d, %lf\n", idNumber, partNumber, amountItems, unitPrice);
I am interested in the following fields, with the rest being ignored. For instance, in record:
"Govan, Guthrie (N210) AX299 x 6 $149.94"
I want N210, AX299, 6, and 149.94 in my variables, in that order.
Result is as follows:
andrew#levin-Inspiron-3650:~/Desktop/schoolwork/project2$ ./a.out
, , 0, 0.000000
, , 0, 0.000000
, , 0, 0.000000
Expected output is:
N210, AX299, 6, 149.94
N106, AX350N, 2, 63.98
N1402, AV2814, 10, 34.90
Please share help!
This is not code directly from my program but a "helper" file I created on the side just to debug this one issue very simply without having to invoke the entire application!
The following similar code worked well for a different format:
Record being:
N210 AX299 6 24.99
in following code:
struct record *current = malloc(sizeof(struct record *));
current->idNumber = (char *)malloc(sizeof (char *) * 8);
current->partNumber = (char *)malloc(sizeof (char *) * 10);
sscanf(line, "%s %s %d %lf", current->idNumber, current->partNumber,
&(current->amountItems), &(current->unitPrice));
I do not expect this code to be a wealth of C beauty, I am a Java developer this is a C project for community college. But can you help me debug this one sscanf problem.
Thank you!
There is a problem with the dynamic allocation here. The line char *idNumber = (char *)malloc(sizeof (char*)); allocates space for a pointer to char, not for a char, or an array of chars. This should be something like:
char *idNumber = malloc(sizeof (char) * 256);
or:
char *idNumber = malloc(sizeof *idNumber * 256);
Note that there is no need to cast the result of malloc() in C. The second version is a very idiomatic way to do this in C. By avoiding use of an explicit type in the operand to sizeof, this is easier and less error-prone in the coding, and easier to maintain when types change during the life of the code. But, since sizeof (char) is always 1 in C, this might as well be:
char *idNumber = malloc(256);
No point in being stingy with allocations, and 256 gives plenty of space for input. And please remember to always check that allocation was successful before attempting to use allocated memory; and don't forget to free malloced memory when finished with it.
But, this is not causing the trouble. The problem is that the format string tells sscanf() to match a comma after the first string, yet in the input this comma is consumed by %*s. There is no further match, so sscanf() returns. There is a further problem with %s) consuming the ) at the end of the input string, leaving no closing parenth to match in the format string. And the %s conversion specifier reads strings up to a whitespace character, so "Van Halen," is consumed by %*s %*s, leaving "Edward" for an attempted match with (%s). These sorts of errors are detectable; one should always check the value returned by calls to scanf() family functions to be certain that input is as expected.
The scanset directive can be used to good effect here. This directive: %*[^(]( tells scanf() to match any characters until a ( is encountered, suppressing assignment, and matching the ( in the end before continuing. Then the %255[^)]) directive tells scanf() to match up to 255 characters, until a ) is encountered, storing the results in an array, and matching the ) in the end before continuing. Note the specification of a maximum width here to prevent buffer overflow, and note that room must be left for the \0 terminator which will always be added by scanf().
Here is a modified program which will work as expected:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *idNumber = malloc(256);
if (idNumber == NULL) {
perror("Allocation failure");
exit(EXIT_FAILURE);
}
char *partNumber = malloc(256);
if (idNumber == NULL) {
perror("Allocation failure");
exit(EXIT_FAILURE);
}
int amountItems = 0;
double unitPrice = 0;
char *line1 = "Govan, Guthrie (N210) AX299 x 6 $149.94";
char *line2 = "Mustaine, Dave (N106) AX350N x 2 $63.98";
char *line3 = "Van Halen, Edward (N1402) AV2814 x 10 $34.90";
if (sscanf(line1, "%*[^(]( %255[^)]) %255s x %d $%lf",
idNumber, partNumber, &amountItems, &unitPrice) < 4) {
fprintf(stderr, "Input error in line1\n");
} else {
printf("%s, %s, %d, %f\n",
idNumber, partNumber, amountItems, unitPrice);
}
if (sscanf(line2, "%*[^(]( %255[^)]) %s x %d $%lf",
idNumber, partNumber, &amountItems, &unitPrice) < 4) {
fprintf(stderr, "Input error in line2\n");
} else {
printf("%s, %s, %d, %f\n",
idNumber, partNumber, amountItems, unitPrice);
}
if (sscanf(line3, "%*[^(]( %255[^)]) %s x %d $%lf",
idNumber, partNumber, &amountItems, &unitPrice) < 4) {
fprintf(stderr, "Input error in line3\n");
} else {
printf("%s, %s, %d, %f\n",
idNumber, partNumber, amountItems, unitPrice);
}
free(idNumber);
free(partNumber);
return 0;
}
Program output:
N210, AX299, 6, 149.940000
N106, AX350N, 2, 63.980000
N1402, AV2814, 10, 34.900000
Your format strings simply do not match the argument types. Rather than going one-by-one trying to point out every error here, the way to prevent this is to enable compiler warnings. For example if you're using GCC or Clang, add -Wall -Wextra -Werror to your compiler command. Then, the compiler will tell you everything you need to know about format string mismatches.

Find string in text file in C

I'm trying to search a text file using C for a string of characters that will always be in a specific place. Specifically I'm looking for three sequential dashes. When it finds the three dashes it should return the line on which it was found. It should then continue to the next line and continue searching for the three sequential dashes until it reaches the end of the file. Each time is should print the line number.
This is what I have so far:
int main() {
FILE *f;
char inName[80];
printf("Read text from: ");
scanf(" %79[^\n]s\n", inName);
f = fopen(inName, "r");
if (f == 0) printf("ERROR: Cannot open file %s for reading.\n", inName);
int lineNumber = 0;
for(;;) {
char line[127];
fgets(line, 127, f);
if (!feof(f)) {
lineNumber++;
} else {
break;
}
double lf;
int d, d1;
char s[30];
char s1[4];
sscanf(line, " %d, %s, %s, %s, %s, %d, %d, %lf",
&d, &s, &s, &s, &s, &d, &s1, &lf);
if (s1 == "---") {
printf("%d\n", lineNumber); // what line
}
}
fclose(f);
return(0);
}
This code runs but does not print anything. Could anyone show how to get this done? Thanks :)
if (s1 == "---")
You're comparing strings the wrong way, you should use strcmp()
follow this example
http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1057537653&id=1043284385
This is not how to compare strings in C:
if (s1 == "---")
as is comparing the address of s1 with the address of the string literal "---".
Use strcmp():
if (strcmp(s1, "---") == 0)
{
Always check the return value of sscanf() to ensure the variables have actually been assigned a value before attempting to use them. The , comma character is not treated as delimiter when processed with "%s" format specifier, only whitespace is used as delimiter. To prevent the consumption of the , use a scan set, similar to how you have done earlier in the program (note corrections to sscanf() arguments):
if (sscanf(line,
" %d, %29[^,], %29[^,], %29[^,], %29[^,], %d, %3[^,], %lf",
&d, s, s, s, s, &d, s1, &lf) == 8)
{
}
You cannot compare char[] with ==. Use strcmp instead.
if( strcmp(s1, "---") == 0 )

Working with Char in c programming

I am a newbie in c programming language and I have a university tutorial assignment that is related with working with chars(I wont be graded for this assignment) where you have to count words, I have to compile and submit my answers in an online web environment where my code will run against test cases that are not visible to me.here is my assignment:
Write the function 'wc' which returns a string containing formatted as follows: "NUMLINES NUMWORDS NUMCHARS NUMBYTES" .
Whitespace characters are blanks, tabs (\t) and new lines (\n). A character is anything that is not whitespace. The given string is null-char (\0) terminated.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* wc(char* data) {
char* result ;
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
char* empty=NULL;
while(strstr(data,empty)>0){
numWords=1;
for (i = 0; i < sizeof(data); i++) {
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
this code will give me the correct output result but I am missing something here at least the test tells me that.
You've got a very serious error:
char* result;
...
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
This is not allowed in C. You need to allocate sufficient memory for the string first. Declare result as a large enough static array, or use malloc if you've covered that in your course.
e.g.
char buf[100]; // temporary buffer
sprintf(buf, "%d %d %d %d", numLine, numWords, numChars, numBytes);
char *result = malloc(strlen(buf) + 1); // just enough for the string
strcpy(result, buf); // store the string
return result;
What if you have this input?
Two Words.
You have to count the transitions between whitespace/non-whitespace, not just count spaces.
Also, I'm pretty sure strstr(data,NULL) will not do anything useful.
You also appear to be missing the \t for tab in your white space checker, and you're not correctly checking when you're in or out of a word. You can use the boolean type bool for this defined in stdbool.h for this.
Source code of wc unix command:
http://www.gnu.org/software/cflow/manual/html_node/Source-of-wc-command.html
All test cases handled.
1) sizeof is wrong:
Instead of sizeof operator you need to use strlen() in for loop, like:
for (i = 0; i < strlen(data); i++)
^ not sizeof
sizeof(data) returns only size of data pointer address that is 4. Because you are to read all char in data[] you need strlen() that will return length of data[] (or number of chars in data[])
2) memory error:
Next Error I can notice there is no memory allocated for result. it declare like:
char* result ;
and No memory allocate! and you are writing using sprintf that cause undefined behavior of your code
3) while(strstr(data,empty)>0) is wrong
strstr() search position of a string in to other you empty string is NULL , CHECK:
char *strstr(const char *s1, const char *s2);
you strstr() always returns data, Why are you calling this? I believe you don't need this while() loop.
I improved you code upto some extend as below, There was only three error as I mentioned above now corrected(to understand read comments), You basic algo is correct:
#define SIZE 256 // added size macro
char* wc(char* data)
char* result = malloc(SIZE*sizeof(char)); //(2) allocated memory for result
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
numWords=1;
// (3) remove while loop
for (i = 0; i < strlen(data); i++) { //(1) change size
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
int main(){
printf("\nresult: %s\n", wc("q toei lxlckmc \t \n ldklkjjls \n i \t nn "));
return 1;
}
Output:
result: 2 14 28 41

Resources