wcstok() not working correctly? - c

I'm trying to get each line in a loop for a wchar_t string using wcstok(), that string is supposed to contain at least two lines, the latest 'wcstok(0, L"\n")' is getting always null result and I'm getting the value of i using printf as 1 only instead of 2 or higher, but the problem got solved when doing #if 0 instead of #if 1.
this is the code below:
wchar_t* w;
wchar_t* line;
int j;
wchar_t**** lines;
int** linescount;
......
int i=0;
#if 1 //problem get solved when changing to #if 0
line = wcstok(w, L"\n");
do{
((*linescount)[j])++;
}while(line=wcstok(0, L"\n"));
(*lines)[annex] = calloc(sizeof(wchar_t**), (*linescount)[j]);
#endif
line = wcstok(w, L"\n");
do{
#if 1 //problem get solved when changing to #if 0
(*lines)[j][i] = calloc(sizeof(wchar_t*), wcslen(line)+1);
wcscpy((*lines)[j][i], line);
#endif
i++;
}while(line=wcstok(0, L"\n"));
printf("i = %d\n", i); /*prints the i value to check if the latest line=wcstok(0, L"\n") worked correctly or not*/
so what's supposed the cause of this problem? and how can I solve it? please help.

The wcstok modifies the string passed in as argument so once you have run your loop to count lines the buffer is basically kaputt.
It seems like overkill to use wcstok to count lines when you easily could just loop through the buffer counting number of \n.

Related

Processing file extensions in C

I'm developing some code in C that reads a file extension and stores it as a code in a byte together whether a text file or binary file is being processed. Later I wish to recover the file extension that is encoded in a byte.
As a test I created a loop in the main function where I can test out the function fileExtenCode(), which is in the second listing.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define EXLEN 9
#define EXNUM 8
typedef unsigned char BYTE;
bool fileExtenCode(char*, BYTE*, int*);
int main(void) {
char fileExten[EXLEN];
BYTE code;
int bin;
for (;;) {
printf("Type file extension: ");
scanf_s("%s", fileExten, EXLEN);
if (fileExten[0] == '.') break;
printf("%s\n", fileExten);
code = 0;
bin = 0;
bool extFound = fileExtenCode(fileExten, &code, &bin); // <== (1)
if (extFound) printf("Extension found: TRUE\n");
else printf("Extension found: FALSE\n");
printf("%s%d", "Code: ", code);
if (bin) printf(" binary file\n");
else printf(" text file\n");
printf("\n");
printf("Type code: ");
int icode;
scanf_s("%d", &icode);
code = icode;
bin = -1;
fileExtenCode(fileExten, &code, &bin); // <== (2)
printf("%s", fileExten); // <== (5)
printf("\n");
}
return 0;
}
The function that I'm trying to test is as follows:
bool fileExtenCode(char* ext, BYTE* code, int* binary) {
char *fileEx[EXNUM] = {
"jpg1", "txt0", "html0", "xml0", "exe1", "bmp1", "gif1", "png1"};
if (*binary < 0) { // <== (3)
ext = fileEx[*code]; // <== (4)
return true;
}
size_t extLen = strlen(ext);
for (BYTE i = 0; i < EXNUM; i++) {
if (strncmp(fileEx[i], ext, extLen) == 0) {
*binary = (fileEx[i][extLen] == '1') ? 1 : 0;
*code = i;
return true;
}
}
return false;
}
The idea is that you pass a string with the file extension to fileExtenCode() in statement (1) in main, and the function searched for that extension in an array, and if found returns true together with the code argument indicating the position in array of file extensions and the binary flag as 0 or 1 indicating if the file is text or binary. A '0' or '1' immediately follows file extension in the array. If the extension is not found, the function returns with false and the return values in the arguments have no meaning.
So far so good, and this part works correctly. However, in using the function in reverse to recover the file extension given the input value of code, it fails when called with statement (2) in main. In this case binary is set to -1, and then the function is called and the condition at (3) is now true and ext in (4) recovers the file extension. This is confirmed when inserting a temporary print statement immediately after (4), but this value is not returned in (5) back in main, and an old input value is instead printed.
Obviously there is a problem with pointers, but I cannot see an obvious way of fixing it. My question is how to correct this without messing up the rest of the code, which is working correctly? Note that char* ext and BYTE* code are used for both input and output, whilst int* binary is used as an input flag and returns no useful value when set to -1.
Once this problem is fixed, then it should be relatively easy to separate the binary flag from the extension when the binary flag is set to -1. Eventually I plan to have many more file extensions, but not until this is working correctly with a sample of 8.
Getting help in fixing this problem would be most appreciated.
OK, many thanks pmg, that works, except that I have to use:
strcpy_s(ext, EXLEN, fileEx[*code]);
as the Visual Studio 2022 compiler flags an error. This also solves a warning I was getting when I declared the array *fileEx[EXNUM] with the const keyword.
In my haste last night I omitted to include the statement:
if (*code >= EXNUM) return false;
immediately after (3) to trap the case when *code goes out of bounds of *fileEx[EXNUM].

How do I read a text file and store it in an array in C programming (values seperated by a comma)?

I need help with getting datapoints, x and y values from a txt file into two arrays.
Currently, the text file consists of 5 lines like:
0.116
0.118
0.12
0.122
0.124
This is my code:
#include <stdio.h>
#include <stdlib.h>
main(void)
{
FILE *inp; /* pointer to input file */
double item;
int cnt=0,y,d,i;
double array[300],swap;
/* Prepare files for input */
inp = fopen("testdoc.txt", "r");
/* Read each item */
while ( (fscanf(inp, "%lf", &item) == 1) && (!feof(inp)) ) {
array[cnt] = item;
cnt++;
}
for (int i = 0; i < cnt; i++)
{
printf("%lf\n",array[i]);
}
printf("The total number of inputs is %d",cnt);
fclose(inp); /* Close the files */
return (0);
}
This only reads the first half of the file, which are the x values. Of which output is
0.116000
0.118000
0.120000
0.122000
The total number of inputs is 4
However, I want to read a text file and store the values in two different arrays for x and y values.
The new text file will look like this
0.116,-0.84009
0.118,4.862
0.12,-1.0977
0.122,0.22946
0.124,3.3173
How do i go changing my code above to recognize the Y values after "," sign? And to add both into two arrays at once?
I tried compiling your code posted on pastebin and received an error because of a missing bracket in your while statement.
That's an easy fix.
The larger issue is in the condition of the while loop.
fscanf returns the number of input items converted and assigned on each call.
When you modified your code to return two values, the condition in the while loop fscanf(inp, "%lf,%lf", &v1,&v2) == 1 would fail and the loop will not be entered.
Please modify the while statement to (have included the missing "(" too)..
while ( (fscanf(inp, "%lf, %lf", &v1, &v2) == 2) && (!feof(inp)) )
and you should be good to go!!!
In addition it would be a good practice to include the return type of int for the main function.

sscanf cannot detect a number C

So I wrote this function in C using sscanf:
int parse_charstar(char *pointah)
{
int numbeh;
int retaahn = sscanf(pointah,"%*[^0123456789]%d",&numbeh);
printf("\n prent deeh numbeeh %d \n",numbeh);
return numbeh;
}
I want to get a number out of a string if there, for eg.
"hello 121"
number: 121
Currently using the above I'm getting garbage values, can someone help?
EDIT:
So I found something interesting today. Apparently, this is what was happening!
My code was never wrong to begin with as pointed out by luoluo and dasblinkenlight.
Problem was how I was calling the program. I'm on linux.
I was calling it as:
parse_charstar("1000");
Output:
prent deeh numbeeh -1634553883
I tried:
parse_charstar(" 1000 "); // added spaces
Output?
prent deeh numbeeh 1000
Spot on.
Now can someone tell me why this happens?
EDIT!!!
Hell with it guys, use strtol , its made for this stuff.
http://www.cplusplus.com/reference/cstdlib/strtol/
Code copied shamelessly from the above page:
#include <stdio.h> /* printf */
#include <stdlib.h> /* strtol */
int main ()
{
char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff";
char * pEnd;
long int li1, li2, li3, li4;
li1 = strtol (szNumbers,&pEnd,10);
li2 = strtol (pEnd,&pEnd,16);
li3 = strtol (pEnd,&pEnd,2);
li4 = strtol (pEnd,NULL,0);
printf ("The decimal equivalents are: %ld, %ld, %ld and %ld.\n", li1, li2, li3, li4);
return 0;
}
A more restricted version of your sscanf would be
int retaahn = sscanf(pointah,"%*[^0-9]%d%*[^0-9]",&numbeh);
Note that this doesn't change anything in your format string. I have just used 0-9 to mention the range and added a second %*[^0-9] to make things more explicit.
Currently using the above I'm getting garbage values, can someone
help?
Probably because you're not passing the right arguments to the function. Just do a
printf("pointah : %s\n",pointah);
to see what is passed or set breakpoints and debug your program.
So since my code was never wrong, it turns out my problem was how I was calling this function.
This is how I solved it:
I was calling it as:
parse_charstar("1000");
I tried:
parse_charstar(" 1000 "); // added spaces
And it worked!
Check my edit above for more!!

Parsing a tab-delimited text file

I'm trying to write a code that will parse a tab-delimited text file by assigning each string between tabs to a given element of a sample struct that I've defined. In the input file, the first row will have all the class identifiers (c_name), the second row will have all the sample identifiers (s_name), and the rest of the rows will contain data.
I know it's going to be a bit more complicated because the first column will actually just contain labels, but I figured I'd start with trying to figure out the general parsing scheme.
I can gather that, for the class identifiers for example, I should probably be using fscanf in a for loop add each identifier to the class field of a given sample, but I'm getting lost in the actual implementation. Based on one post I saw, I thought I could do something along the lines of using %[^\t]\t in fscanf to read into an array everything that's not a tab up to a tab, but I don't think I have this quite right.
Any suggestions would be greatly appreciated.
#define LENGTH 30
#define MAX_OBS 80000
typedef struct
{
char c_name[LENGTH];
char s_name[LENGTH];
double value[MAX_OBS];
}
sample;
// I've already calculated the number of columns in the file
sample sample[total_columns];
for (int i = 0; i < total_columns; i++)
{
fscanf(input, "%[^\t]\t", sample[i].s_name);
}
Edit: I've tried several different variations of the code below ("%[^\t\n\r]\t\n\r", or "%[^\t\n\r]%*1[\t\n\r]", or " %[^\t\n\r]") and they all seem to be generally working except that, depending on the size I'm allocating to data and how long I'm iterating, it gives a segmentation fault at some point. The code below gives a segmentation fault immediately, but if I arbitrarily change total_columns in both places to 3, it will print Class Case Case. This seems to work up until 14, at which point the whole program segmentation faults. I'm fairly confused about the issue here. I've also tried mallocing memory to the sample data array to see if it was an issue of stack vs heap, but that doesn't seem to be helping either. Thanks so much for your help!
sample data[total_columns];
fseek(input, 0, SEEK_SET);
for (int i = 0; i < total_columns; i++)
{
fscanf(input, "%[^\t\n\r]\t\n\r", data[i].s_name);
printf("%s\n", data[i].s_name);
}
An example input file would look like:
Class Case Case Case Case Case Case Case Case Case Case Case Case Case Case Control Control Control Control Control Control Control Control Control Control Control Control Control Control Control Control
Subject G038 G144 G135 G161 G116 G165 G133 G069 G002 G059 G039 G026 G125 G149 G108 G121 G060 G140 G127 G113 G023 G147 G011 G019 G148 G132 G010 G142 G020 G021
Data1 0.000741628 0.00308607 0.000267431 0.001418697 0.001237904 0.000761145 0.0008281 0.002426075 0.000236698 0.004924871 0.000722752 0.003758006 0.000104813 0.000986619 0.000121803 0.000666854 0 0.000171394 0.000877993 0.002717391 0.001336501 0.000812089 0.001448743 5.28E-05 0.001944298 0.000292529 0.000469631 0.001674047 0.000651526 0.000336615
Data2 0.102002396 0.108035127 0.015052531 0.079923731 0.020643362 0.086480609 0.017907667 0.016279315 0.076263965 0.034876124 0.187481931 0.090615572 0.037460171 0.143326961 0.029628502 0.049487575 0.020175439 0.122975405 0.019754837 0.006702899 0.014033264 0.040024363 0.076610375 0.069287599 0.098896479 0.011813681 0.293331246 0.037558052 0.303052867 0.137591517
Data2 0.218495065 0.242891829 0.23747851 0.101306336 0.309040188 0.237477347 0.293837554 0.34351816 0.217572429 0.168651691 0.179387106 0.166516699 0.099970652 0.181003474 0.076126675 0.10244981 0.449561404 0.139257863 0.127579104 0.355797101 0.354544105 0.262855651 0.10167146 0.186068602 0.316763006 0.187466247 0.05701315 0.123825467 0.064780343 0.069847682
Data4 0.141137543 0.090948286 0.102502388 0.013063365 0.162060849 0.166292135 0.070215996 0.063535037 0.333743609 0.131011609 0.140936687 0.150108506 0.07812762 0.230704405 0.069792935 0.120770743 0.164473684 0.448110378 0.42599534 0.074094203 0.096525097 0.157661185 0.036737518 0.213931398 0.091119285 0.438073807 0.224921728 0.187034237 0.06611442 0.086005218
Data5 0.003594044 0.003948354 0.008137536 0.001327901 0.002161974 0.003552012 0.002760334 0.001898667 0.001420186 0.003165988 0.001011853 0.001217382 0.000314439 0.004254794 0.000213155 0.003650147 0 0.002742309 0.002633978 0 0.002524503 0.002146234 0.001751465 0.006543536 0.003941146 0.00049505 0.00435191 0.001944054 0.001303053 0.004207692
Data6 0.000285242 2.27E-05 0 1.13E-05 0.0002964 3.62E-05 0.000138017 0.000210963 0.000662753 0 0 0 0 4.11E-05 0 0 0 0 0.000101307 0 0 0 0 5.28E-05 0.00152391 0 0 0 0 0
Data7 0.002624223 0.001134584 0.00095511 0.000419934 0.000401011 0.001739761 0.00272583 0.002566717 0.000520735 0.002311674 0.006287944 0 6.29E-05 0.000143882 3.05E-05 0.000491366 0 0 3.38E-05 0 0.001782002 0.000957104 0.002594763 0.000527704 0.000105097 0.001192619 3.13E-05 0 0.000744602 0.000252461
Data8 0.392777683 0.383875286 0.451499522 0.684663315 0.387394299 0.357992026 0.488406597 0.423473155 0.27267563 0.47454646 0.331020526 0.484041709 0.735955056 0.338841956 0.781699147 0.625403622 0.313596491 0.270545891 0.379259109 0.498913043 0.372438372 0.446271644 0.606698813 0.305593668 0.360535996 0.29889739 0.328710081 0.521222594 0.419924299 0.584111756
Edit: I seem to have fixed it by changing the MAX_OBS definition - pretty sure I have a fundamental misunderstanding of what that actually means. I'll have to look into that. Thanks again for the help!
try this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LENGTH 30
#define MAX_OBS 80000
typedef struct{
char c_name[LENGTH];
char s_name[LENGTH];
double value[MAX_OBS];
} Sample;//Duplication of type and variable names should be avoided. pointed out by Jonathan Leffler.
int main(void){
char line[1024];
FILE *input = fopen("data.txt", "r");
fgets(line, sizeof(line), input);
int total_columns = 0;
char *p = strtok(line, "\t\n");
while(p){
++total_columns;
p = strtok(NULL, "\t\n");
}
--total_columns;//first column is field name
rewind(input);
//*******************************************************************************
Sample *sample = malloc(total_columns * sizeof(*sample));//To allocate in the stack is large. So allocate by malloc.
fscanf(input, "%*s\t");//skip first column
for (int i = 0; i < total_columns; i++){
fscanf(input, "%[^\t\n]\t", sample[i].c_name);//\n for last column
}
fscanf(input, "%*s\t");//skip first column
for (int i = 0; i < total_columns; i++){
fscanf(input, "%[^\t\n]\t", sample[i].s_name);
}
int r;
for(r = 0; r < MAX_OBS; ++r){
if(EOF==fscanf(input, "%*s")) break;
for (int i = 0; i < total_columns; i++){
fscanf(input, "%lf", &sample[i].value[r]);
}
}
fclose(input);
//test print
printf("%s\n", sample[0].c_name);
printf("%s\n", sample[0].s_name);
for(int i = 0; i < r; ++i)
printf("%f\n", sample[0].value[i]);
printf("\n%s\n", sample[total_columns-1].c_name);
printf("%s\n", sample[total_columns-1].s_name);
for(int i = 0; i < r; ++i)
printf("%f\n", sample[total_columns-1].value[i]);
free(sample);
}

Segmentation error, what is missing in my code?

I'm trying to get my code to convert a text file with 3 columns, xcoor, ycoor, and a symbol with 2 characters into a 30x30 map that prints the 2nd character of the symbol with the rest of the spaces being filled with a '.' However, my code doesn't seem to run, and I get a segmentation error when I try inputting the text file, what am I doing wrong? Thanks in advance
int main(void)
{
char grid[30][30];
for(int i=0;i<30;i++){
for(int j=0;j<30;j++){
grid[i][j]='.';
}
}
int xcoor,ycoor;
char symbol[2];
while((xcoor!=0)||(scanf("%d",&xcoor)))
{
while(xcoor==0){
scanf("%d",&xcoor);
}
scanf("%d %c%c",&ycoor,&symbol[0],&symbol[1]);
grid[xcoor-1][ycoor-1]=symbol[1];
}
for(int i=0;i<30;i++){
for(int j=0;j<30;j++){
printf("%c ",grid[i][j]);
}
printf("\n");
}
return 0;
}
This may not cover ALL of your errors, but immediately I see this:
int xcoor,ycoor;
char symbol[2];
while((xcoor!=0)
Do you think xcoor has a valid value right now? Should it? Because it doesn't. You've created a variable, then before actually setting it to anything, you are checking its value.
It's more than likely your scanf call that's giving you trouble. Regardless, try actually setting these variables. It will most likely fix your issues.
See here for more info: Is reading from unallocated memory safe?
You are using an uninitialized variable xcoor in the conditional of the while statement.
You can fix that by initializing xcoor.
More importantly, you can simplify the code for reading user data and the related error checks. Here's what I suggest:
while ( scanf("%d%d %c%c", &xcoor, &ycoor, &symbol[0], &symbol[1]) == 4 )
{
if ( xcoor < 0 || xcoor >= 30 )
{
// Deal with problem.
fprintf(stderr, "Out or range value of xcoor: %d\n", xcoor);
exit(1);
}
if ( ycoor < 0 || ycoor >= 30 )
{
// Deal with problem.
fprintf(stderr, "Out or range value of ycoor: %d\n", ycoor);
exit(1);
}
grid[xcoor-1][ycoor-1] = symbol[1];
}

Resources