Saving Char from lex to array of Char in C - c++

I'm saving characters from a c file in this array
char *idTable[100];
Inside a while loop,
if(ntoken == 1){
idTable[numId] = yytext;
printf(" \nVariable %s", idTable[numId]);
printf(" Found\n");
numId++;
}
and then iterate through the array. The variable yytext is supposed to have only identifiers and variables like int i, int j, int cont
When I print those character inside the loop, it shows me the variables that I want to save. But when I iterate the array it takes all the text from the variable to the bottom:
while(i<numId){
printf("%d", i );
printf("%s", idTable[i]);
i++;
}
So,
printf(" \nVariable %s", idTable[numId]);
printf(" Found\n");
Will print characters like Variable i Found But printf("%s", idTable[i]); Will always print text inside from the file I want to see. Something like this:
i;
int j;
char c;
char cadena;
float z;
int 89aa12;
z=14.9e-8;
z= 3454y45hrthtrh;
z== 3454y45hrthtrh;
z= 3454y45hrthtrh;
z=12.9;
cadena="Hola";
scanf ("%d",i);
i=i*2;
printf ("El doble es %d",i);
Y="Cualquier Cosa 1";
u=z+y

You're saving a pointer to the same memory in each element of idTable, so whatever that memory is set to last is what each one will be pointing to.
You need to allocate additional memory for each string you want to save (or use a std::string).
strdup may do what you want.
idTable[numId] = strdup(yytext);
but don't forget to free that memory when you're done with it.

Related

Using char* to store data and error produced

const char* val1 = advertisedDevice.getAddress().toString().c_str();
Serial.printf("Advertised Device: %s \n", val1);
This code is used to retrieve the MAC address of a BLE device.
The output of val1 on the serial monitor is:
Advertised Device: 45:89:a2:d8:74:65
But when I try to output val1 individually the system crashes. The code is shown below. Why is this?
Serial.printf("Val is : %s", val1[0]);
I should expect the serial monitor is print out
Val is : 4
I am also trying to store val1 is a string array, so for example
pseudo-code
String arr[50];
loop{
const char* val1 = advertisedDevice.getAddress().toString().c_str();
Serial.printf("Advertised Device: %s \n", val1);
arr[i] = val1[0]+val1[1]+val1[2]+....+val1[18]
i++;
}
I want to store it in a single array because I then upload it to a database. I cant do this if its in the form of val1[0],val1[1]... and so on. It will be easier to store all the data in a single array location i.e.
arr[1] = "45:47:89:fd:12",
arr[2] = "47:AC:1b:24:58" and so on.
Is this right?
Serial.printf("Val is : %s", val1[0]);
%s expects a string of characters, i.e. a char * or const char * variable. val1 is a const char *, so val1[0] is a char that is the first character within val1. You need to change %s to %c, or else Serial.printf will believe the value of val1[0] is an address to a string of characters, causing a crash or undefined behavior.
If you meant for val1 to be an array of strings, you need to declare it as that. For example:
const char *val1[50];
val1[0] = advertisedDevice.getAddress().toString().c_str();
Serial.printf("Val is : %s", val1[0]); // Now this will work
Edit: If you're looking to build a list of strings out of arr, you should be able to simply assign to arr and access the strings through it:
String arr[50];
loop{
arr[i] = advertisedDevice.getAddress().toString().c_str();
// If above doesn't work, try: arr[i] = String(...);
Serial.printf("Advertised Device: %s \n", arr[i]);
i++;
}

Storing of string literals in consecutive memory locations

#include <stdio.h>
#include <string.h>
int main() {
char *s[] = {"cricket","tennis","football"};
printf(" String are: \n\n");
printf(" %s \n", *(s));
printf(" %s \n", *(s+1));
printf(" %s \n", *(s+2));
printf(" \n\n");
printf(" Starting locations of the string are: \n\n");
printf(" %d\n",*(s));
printf(" %d\n",*(s+1));
printf(" %d\n",*(s+2));
printf(" \n\n");
return 0;
}
OUTPUT:
String are:
cricket
tennis
football
Starting locations of the string are:
134514112
134514120
134514127
s is a array of character pointers. s has three elements and each of them are storing the starting address of the string literals.i.e. s[0] is a pointer pointing to the starting address of "cricket". etc..
My question is :
By observing these addresses we can see that second string is stored just after the null character of the first string. All three strings are stored in sequential form. Is this always true ?
This is a linker decision - to store string literals tightly or not. There is no guaranties. Or even this may be done by compiler - it may create continuous data section that holds all involved literals. But nevertheless actual layout of that section is still implementation-specific and you shouldn't assume anything about it.
I have an example for you:
#include <stdio.h>
#include <inttypes.h>
char *s[] = { "ball", "football" };
int main( void )
{
int i;
for( i=0; i<2; i++ ) {
printf( "%" PRIuPTR "\n", (uintptr_t)s[i] );
// or printf( "%p\n", s[i] ); forr hex output
}
}
If I compile and run that program with gcc -O3 I get:
4195869
4195865
What happens here is that the optimizer merges both string literal to a single "football" so that s[0] becomes s[1] + 4.
That's only one example of what compiler / linker might decide on how to store string literals ...
It will be totally compiler dependent. Compiler can take any address at the time execution started
Only static arrays are contiguous in memory. ex: char s[1024].

Is fprintf not like printf when writing to file?

I've reviewed the documentation:
It says here:
Once a file has been successfully opened, you can read from it using fscanf() or write to it using fprintf(). These functions work just
like scanf() and printf(), except they require an extra first
parameter, a FILE * for the file to be read/written.
So, I wrote my code as such, and I made sure to include a conditional statement to make sure that the file opened:
# include<stdio.h>
# include<stdlib.h>
void from_user(int*b){
b = malloc(10);
printf("please give me an integer");
scanf("%d",&b);
}
void main(){
FILE *fp;
int*ch = NULL;
from_user(ch);
fp = fopen("bfile.txt","w");
if (fp == NULL){
printf("the file did not open");
}
else {
printf("this is what you entered %d",*ch);
fprintf(fp,"%d",*ch);
fclose(fp);
free(ch);
}
}
Am I wrong or is the documentation not explaining this correctly? thanks.
from_user() is not implemented correctly.
The pointer that you create in from_user() will not be passed back to the calling function. To do that, you need a double pointer, or to pass by reference.
In your code, you pass a int ** to scanf(), while it is expecting a variable of int *.
Here's a working implementation:
void from_user(int **b){
*b = malloc(sizeof(int));
printf("please give me an integer");
scanf("%d", *b);
}
int main() {
int *ch;
from_user(&ch);
}
Your File IO
That part is all fine. It's just the value of ch that is broken.
a much simpler from_user implementation
int from_user(){
int i;
printf("please give me an integer");
scanf("%d", &i);
return i;
}
and in main
int ch = from_user();
...
printf("this is what you entered %d",ch);
fprintf(fp,"%d",ch);
Simplest fix to your own code, you don't need to use double pointers, just allocate the memory in main and pass the pointer to your function, like this:
Remove b = malloc(10);
Remove the & before b in scanf
Change int*ch = NULL; to int *ch = malloc(sizeof(int));
Done. Why does it matter where we allocate the memory? See my more detailed answer here: pointer of a pointer in linked list append
Oh and you should move free(ch) out from the else statement.

Reading and printing characters from a user defined text file

I am trying to work out how I can print character by character the contents of a user-defined text file. I believe I have got the retrieval of the file correct but I am unsure how I can print each character.
#include <stdio.h>
#include <ctype.h>
#define ELEMENT 300
#define LENGTH 20
void main(char str[ELEMENT][LENGTH])
{
FILE *infile;
char textfile[1000];
char read_char;
int endoff;
int poswithin = 0;
int wordnum= 0;
printf("What is the name of your text file?: ");
scanf("%s", &textfile);
infile=fopen(textfile,"r");
if (infile == NULL) {
printf("Unable to open the file.");
}
else
{
endoff=fscanf(infile,"%c",&read_char);
while(endoff!=EOF);
{
This is where I believe I'm stuck. The first character is read into the variable read_char but then it doesn't seem to print anything?
if(read_char>=65&&read_char<=90 || read_char<=65)
{
str[wordnum][poswithin]=read_char;
printf("%c", read_char);
poswithin++;
}
else
{
str[wordnum][poswithin]=(char)"\n";
poswithin=0; wordnum++;
}
endoff=fscanf(infile, "%s", &read_char);
}
}
fclose(infile);
}
Typo in the format specifier to your second call to fscanf
endoff=fscanf(infile, "%s", &read_char);
should be
endoff=fscanf(infile, "%c", &read_char);
Also,
str[wordnum][poswithin]=(char)"\n";
shouldn't be casting a string literal to char and probably should be adding a NULL terminator rather than a newline:
str[wordnum][poswithin]='\0';
Finally, you shouldn't try to declare str as an argument to main.
char str[ELEMENT][LENGTH];
int main() // or int main(int argc, char* argv[])
Using fscanf with %c format specifier is overkill for reading a single character from a file.
Try fgetc to read one character. The function avoids the overhead of parsing a format specifier string and variable number of arguments.
A more efficient method is to allocate a buffer or array and read "chunks" of chars from a file, using fread. You can then scan the buffer or array. This has less function call overhead than many calls to read single bytes. Efficient buffer sizes are multiples of 512 to conform with disk drive sector sizes.

Segfaults on appending char* arrays

I'm making a lexical analyzer and this is a function out of the whole thing. This function takes as argument a char, c, and appends this char to the end of an already defined char* array (yytext). It then increments the length of the text (yylen).
I keep getting segfaults on the shown line when it enters this function. What am I doing wrong here? Thanks.
BTW: can't use the strncpy/strcat, etc. (although if you want you can show me that implementation too)
This is my code:
extern char *yytext;
extern int *yylen;
void consume(char c){
int s = *yylen + 1; //gets yylen (length of yytext) and adds 1
//now seg faults here
char* newArray = new char[s];
for (int i = 0;i < s - 1;i++){
newArray[i] = yytext[i]; //copy all chars from existing yytext into newArray
}
newArray[s-1] = c; //append c to the end of newArray
for (int i = 0;i < s;i++){ //copy all chars + c back to yytext
yytext[i] = newArray[i];
}
yylen++;
}
You have
extern int *yylen;
but try to use it like so:
int s = (int)yylen + 1;
If the variable is an int *, use it like an int * and dereference to get the int. If it is supposed to be an int, then declare it as such.
That can t work:
int s = (int)yylen + 1; //gets yylen (length of yytext) and adds 1
char newArray[s];
use malloc or a big enought buffer
char * newarray=(char*)(malloc(s));
Every C-style string should be null-terminated. From your description it seems you need to append the character at c. So, you need 2 extra locations ( one is for appending the character and other for null-terminator ).
Next, yylen is of type int *. You need to dereference it to get the length (assuming it is pointing to valid memory location ). So, try -
int s = *yylen + 2;
I don't see the need of temporary array but there might be a reason why you are doing it. Now,
yytext[i] = newArray[i]; //seg faults here
you have to check if yytext is pointing to a valid write memory location. If yes, then is it long enough to fill the appending character plus null terminator.
But I would recommend using std::string than working with character arrays. Using it would be a one liner to solve the problem.