I was working on an assignment for a simple assembler that should recognize arbitrary variable names like high programming languages. I tried to use Dynamic allocation to an array of char pointers
I am just trying to make an extensible array of strings and being able to search this array for specific strings But it gives a segmentation fault on the line of trying to compare the two strings [line: 14]
Comp(&buffer[1], Variables[i];
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define Comp(a,b) strcmp(a,b) == 0 ? 1 : 0
char buffer[255], **Variables;
int VariableIndex;
void A_instructionHandler() {
int A_Operand, test = 0;
if (buffer[0]== '#') {
for (int i = 0; i <= VariableIndex; i++) {
test = Comp(&buffer[1], Variables[i]);
if (test) {
A_Operand = i + 16;
break;
}
}
}
}
int main(int argumentCounter, char *arguments[]) {
strcpy(buffer, "#variable");
Variables = (char **)calloc(VariableIndex + 1, sizeof(char**));
A_instructionHandler();
}
Here's that code refactored into something more idiomatic:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void instruction_handler(char* buffer, char** variables) {
switch (buffer[0]) {
case '#':
// This iterates over the NULL terminated array by stopping when
// it hits a NULL pointer, or in other words *v is false.
for (char **v = variables; *v; ++v) {
// If this matches a variable name...
if (!strcmp(*v, &buffer[1])) {
// Variable matched, so show some debugging code
printf("Found variable: %s\n", *v);
return;
}
}
}
}
int main(int argc, char* argv[] ) {
// Create a simple NULL-terminated array of arbitrary size
char *variables[] = {
"variable",
NULL
};
instruction_handler("#variable", variables);
}
Where that variables array can be defined however you like, extended, shrunk, so long as the NULL terminator remains in place at the end.
Some tips based on your original code:
Don't use global variables unless you have an extremely compelling reason. No such reason existed here.
Make your functions clear in intent and purpose.
Pick a naming convention and stick to it.
Use C conventions like strcmp() and just deal with how weird it is, don't wrap that in a #define and invent your own C dialect nobody understands. You'll get used to C over time, it won't bother you as much, and you can code without driving other people on your team up the wall.
Explanations like argc expanded to argumentCounter is better expressed as a comment than an awkwardly long variable name, especially one that's very non-standard. Comments are great. Use them as much as you like!
Related
This is my first time working with dynamic arrays and I am honestly just so confused. My original array(below) works fine.
#include <stdio.h>
int main()
{
char icdC[4][10];
for(int i =0;i<4;i++){
for(int j=0;j<10;j++){
printf("What are your ICD codes [%d][%d]\n",i,j);
scanf("%s", &icdC[i][j]);
}
}
return 0;
}
However I tried converting this array into a double dynamic array (below) it doesn't seem to work correctly as it will either tell me "signal: segmentation fault (core dumped) or it just won't run.
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
int main()
{
char** icdC;
icdC = (char**)malloc(4*10*sizeof(char));
for(int i=0;i<4;i++){
for(int j=0;j<10;j++){
printf("What are your ICD codes [%d][%d]\n",i,j);
scanf("%s", &icdC[i][j]);
}
}
return 0;
}
The issue seems to be located within icdC = (char**)malloc(4*10*sizeof(char));, as it is an incorrect reference to the second array you're trying to create.
In C there are many options to represent a 2d array, among which the possibility to
create an array of pointers, each of which points to a specific row. Then you can allocate the memory for each array using the malloc, which allows you to generate an "array of pointers".
The implementation would most likely be:
char ** icdC;
int r = 4, c = 10;
icdC = (char*) malloc(sizeof(char*) * r);
for (int i = 0; i < r; i++) {
icdC[i] = malloc(sizeof(char) * c);
}
Note: You can also do this implementation in two loops as you did above.
From here you can do a nested loop to scan the value like you've already done in your snippet. Remember that now you can access a value by indicating the index for the corresponding row and column, like this: icdC[row_num][row_column] = .....
It might look strange at the beginning, but after you get a grasp of the concept, it's all good and fun!
I'll summarize the problem that goes in my homework:
"Write a recursive function that receives a char array given by the user, prints it backwards and doesn't return anything. The function must end the process and return when \0 is found". Don't use the string.h library, and don't use pointers."
I kind of managed to get the recursive way of doing it, but I'm failing at the function definition.
This is nothing more than a revamp of Gardener's answer, without technically using pointers (because there are no little * thingies).
#include <stdio.h>
void recursive_print(char array[]) {
if (array[0] != '\0') {
recursive_print(array + 1); //pointer arithmetic, but no '*', so not a pointer supposedly
printf("%c", array[0]);
}
else {
printf("\n"); // send a new line at the end to make it look better.
}
}
int main() {
char string[] = "Hello";
recursive_print(string);
return 0;
}
Although, I would add that if your instructor is making this (counter-productive) distinction about the use of pointers, you might want to remember that just as all books about C are not equally good, the same thing can be said of instructors.
Here is one way of doing it. With recursive functions, the biggest problem is making sure you have the right exit condition.
#include <stdio.h>
void recursive_print(char* array) {
if(*array != '\0') {
recursive_print(&array[1]);
printf("%c", *array);
} else {
printf("\n"); // send a new line at the end to make it look better.
}
}
int main()
{
char string[] = "Hello";
recursive_print(string);
return 0;
}
I'm trying to code a Turing machine in C.
But my program doesn't work, it gets stuck in an endless loop.
Here's my code with some explanations:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 3 //number of different states for the cells
#define K 20 //length of the tape
typedef struct
{
int state;
int head;
char tape[];
}mt; //machine
void init_mt(mt* machine, char val[], int n)
{
machine->state=1; //edited mistake
machine->head=0; // edited mistake
int i;
for(i=0;i<n;i++)
{
machine->tape[i]=val[i];
}
}; //initialization of a machine
typedef struct
{
char write;
char direction;
int state;
}actions; //actions composed of three instructions
typedef struct
{
actions exec01;
actions exec02;
actions exec11;
actions exec12;
}program; //program composed of four actions
void execute(actions exec, mt mach)
{
mach.tape[mach.head] = exec.write;
mach.state = exec.state;
if(exec.direction == 'R')
{
mach.head++;
}
else
{
mach.head--;
}
} //class that follows the instructions from the actions
void execute2(mt mach, program p)
{ do{
printf("%c %d %d \n", mach.tape[mach.head], mach.head, mach.state );
if(mach.tape[mach.head] == 0)
{
if(mach.state == 1)
{
execute(p.exec01, mach);
}
else if(mach.state == 2)
{
execute(p.exec02,mach);
}
}
else if(mach.tape[mach.head] == 1)
{
if(mach.state == 1)
{
execute(p.exec11,mach);
}
else if(mach.state == 2)
{
execute(p.exec12,mach);
}
}
}while( (mach.head<K) && (mach.state != 3));
} // class that read the program and act according to the states of the cells,
//keeps going until the machine is at the third state or if it reaches the end of the tape
int main(){
mt machine;
char t[10]={'1','1','1','0','0','1','0','1','0','1'};
init_mt(&machine, t, 10);
program p ={ {'0','R',1}, {'0','R',1}, {'1','R',2}, {'0','L',3} };
execute2(machine, p);
return 0;
} //main with a tape composed of 10 cells and a program composed of four actions
This program keeps displaying "0,0,1" indefinitely and I can't find the error.
Thanks for the help and sorry if this unclear.
There are a few problems here:
In some instances you're passing your structures as arguments, rather than pointers to them. This creates local copies of the entire structures in the called function. Any changes made to those copies will be lost when the functions return. It is also inefficient. Just pass structure pointers.
You aren't declaring any space for tape in your structures, so it's basically a zero-length array. Any kind of access whatsoever will corrupt memory and result in undefined behavior. You have a couple choices here. You can either choose some fixed size for it, and use that for the array size, or you can change it to a pointer and dynamically allocate storage for it. One way or another, you have to allocate the storage.
In execute2, it's comparing mach.tape[mach.head] to the integers 0 and 1. But the tape doesn't contain those values. It contains the characters '0' and '1'. So surround those constants with single quotes. It would also be a good idea to print an error if an unexpected value is encountered. That would have caught this problem instantly.
In function execute, you pass the structure mach by value. In that function you also perform
mach.head++
This, value presumably should be given back to the function execute2. So you will have to pass the structure mach by reference to this function.
I finally managed to make my regex function work, but I want to know if I can possibly reduce the number of pointer declarations in the main function to one. For example, I want to convert:
int main(){
regex* r=calloc(1,300000);
regex* rr=r;
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
printres(r);
}
free(r);
return 0;
}
to something like:
int main(){
regex* r=calloc(1,300000);
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&r)==0){
printres(r);
}
free(r);
return 0;
}
but as it stands, this won't work because the regexmatch function seems to change the address of the variable which causes the program to crash at free(r);
I even tried adding reg=rp; just before the last return statement in the function in hopes that I reset the struct variable address to what it was when the function was first called, but that didn't work.
What can I do to fix this? or is my only option to use two pointers in my main function?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
typedef struct{
char str[1000];
} regex;
long regexmatch(const char* str,const char* regexs,const size_t nummatch,regex** rp){
regex** reg=rp;
regex_t r;regmatch_t match[nummatch];
if (regcomp(&r,regexs,REG_EXTENDED) != 0){return -1;}
if (regexec(&r,str,nummatch,match,0)!=0){regfree(&r);return -1;}
regfree(&r);size_t i=0;
for (i=0;i<nummatch;i++){
if (match[i].rm_so > -1){
unsigned long sz=match[i].rm_eo-match[i].rm_so;
if (sz > 0 && sz < 1000){
memcpy((**reg).str,(char*)(str+match[i].rm_so),sz);
(*reg)++;
}
}
}
(**reg).str[0]='\0';
return 0;
}
void printres(regex* r){
printf("Matches\n");
while (r->str[0] != '\0'){
printf("%s\n",r->str);
r++;
}
}
int main(){
regex* r=calloc(1,300000);
regex* rr=r;
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
printres(r);
}
free(r);
return 0;
}
Why do you pass rp by reference? You clearly don't want the value in the calling program to change, so it would be simpler to just pass it directly.
In fact, what you really want that parameter to be is an array of regex objects ([Note 1]). So instead of using the prototype
long regexmatch(const char* str,
const char* regexs,
const size_t nummatch, /* This const is pointless */
regex** rp);
it would make more sense to use:
long regexmatch(const char* str,
const char* regexs,
size_t nummatch,
regex rp[nummatch]);
(Effectively, that's the same as using regex* rp as a parameter, but writing it as rp[nummatch] is more self-documenting. Because you use an empty string as a terminator (which means that you can't handle zero-length captures), you actually need nummatch to be at least one greater than the number of captures in the pattern, so it is not 100% self-documenting.
Having made that change to the prototype, you need to remove one level of indirection in the function:
long regexmatch(const char* str,
const char* regexs,
size_t nummatch,
regex reg[nummatch]){
/* Compiling the regex is the same as in your code. I removed
* the assignment of reg from rp, since the parameter is now
* called reg.
*/
size_t i=0;
for (i=0;i<nummatch;i++){
if (match[i].rm_so > -1){
unsigned long sz=match[i].rm_eo-match[i].rm_so;
if (sz > 0 && sz < 1000){
memcpy(reg->str, (char*)(str+match[i].rm_so), sz);
/* The above memcpy doesn't nul-terminate the string,
* so I added an explicit nul-termination.
*/
reg->str[sz] = 0;
/* I think this should be outside the if statement. Personally,
* I'd put it in the increment clause of the for loop.
* See Note 2.
*/
reg++;
}
}
}
reg->str[0] = 0;
return 0;
}
(See it live on ideone.)
Notes
I found it confusing to call regex what is basically a fixed-length string representing a regex capture. Also, I don't see the point of wrapping the fixed-length character allocation in a struct, unless you plan to assign to values of type regex. But all of that is irrelevant to your basic question.
When you're copying captures into your regex array, you simply ignore captures which are empty, unset, or too long. This means that you cannot access capture i by looking at the ith element in the array. If a previous capture happened to be empty, then the capture will be at position i - 1 (or earlier, if more than one capture were empty), and the empty capture won't be accessible at all. I'm not sure exactly what your goal here is, but that seems hard to use. However, since you use empty strings to indicate the end of the capture list, you cannot insert an empty capture into the list. So you really might want to rethink the API.
A much cleaner approach would be to use an array of pointers to strings (like argv.)
In regexmatch add : regex* rp2=*rp;regex** reg=&rp2;
In your code (*reg)++; is modifying the value of rp. Its equivalent of rp++ in your code because regex** reg=rp;
rp is the pointer adress to your calloc set by &r in regexmatch call.
You dont want to change this pointer. So we use another pointer called rp2.
const char *SITE_NAME = "test";
char SITE_ROOT[19];
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
I can't figure out why I'm getting an error of:
error: expected ‘)’ before string constant
Basically I just want to concatenate the variable SITE_NAME onto SITE_ROOT. The error is on the sprintf line. Any ideas?
UPDATE: So the code works if it is inside main(). I had it outside of main() so that I could use those variables inside of functions.
The error looks like it might not be shown in the code but the sprintf should be:
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
EDIT:
Here is my complete test code if that helps at all:
#include <string.h>
#include <stdio.h>
int main()
{
const char *SITE_NAME = "test";
char SITE_ROOT[19];
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
printf( "%s\n", SITE_ROOT ) ;
return 0 ;
}
As has been pointed out, the direct problem is that you're trying to call sprintf from outside a function.
You mentioned that you are setting the strings this way because you're using SITE_NAME by itself in addition to concatenating it with the path and you want to only have to change it in one place. This is a good goal, known in some circles as "don't repeat yourself" (often abbreviated DRY). However, even if the code worked (say, because you moved the sprintf call into main), you haven't really achieved your goal due to the following line:
char SITE_ROOT[19];
You are declaring a fixed length array exactly big enough to hold "/var/www/html/test", which is just asking for a buffer overflow. When you change SITE_NAME from "test" to, for example, "someRealSiteName", you'll very probably overwrite something else when you concatenate, causing unpredictable results. So you have to manually recalculate the length of the final string and update the array size (which would be easy to get wrong, say by forgetting to add 1 for the null terminator) every time you change SITE_NAME.
You could, of course, limit the length of SITE_NAME and size SITE_ROOT to hold the longest possible path, but it'd be an artificial limit and you might end up wasting space. Furthermore, you'd still have to verify the length isn't exceeded at run-time (or use a function that will ignore extra characters).
Instead, you could dynamically set the size of SITE_ROOT like so:
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
const char SITE_PATH[] = "/var/www/html/";
const char SITE_NAME[] = "someRealSiteName";
char *SITE_ROOT = NULL; // just making this explicit, would be set to 0 anyway
int main(void)
{
size_t siteRootLength = strlen(SITE_PATH) + strlen(SITE_NAME);
SITE_ROOT = malloc(siteRootLength + 1); //don't forget to account for the terminating '\0'
strcpy(SITE_ROOT, SITE_PATH);
strcat(SITE_ROOT, SITE_NAME);
printf("%s\n", SITE_NAME):
printf("%s\n", SITE_PATH):
printf("%s\n", SITE_ROOT):
return 0;
}
This solution is okay, but has some drawbacks:
SITE_ROOT can't be a const pointer , so both the string and the pointer itself could be accidentally changed
Site path and name will each be in memory twice (though it sounds like you're okay with that)
Concatenation is being done at run-time when it could be done at compile-time
Code is longer and more complex than necessary for such a simple task
Risk that SITE_ROOT is used before it has the correct value (or is even a valid pointer/string!) in some other initialization code or another thread.
I feel something like the following is better:
#include <stdio.h>
#define SITE_PATH_MACRO "/var/www/html/"
#define SITE_NAME_MACRO "someRealSiteName"
// the preprocessor will merge the two string literals into one
#define SITE_ROOT_MACRO SITE_PATH_MACRO SITE_NAME_MACRO
// you could do without some or all of these if you don't need them
// (or are willing to use the macros directly)
const char SITE_PATH[] = SITE_PATH_MACRO;
const char SITE_NAME[] = SITE_NAME_MACRO;
const char SITE_ROOT[] = SITE_ROOT_MACRO;
int main(void)
{
printf("%s\n", SITE_NAME);
printf("%s\n", SITE_PATH);
printf("%s\n", SITE_ROOT);
return 0;
}
Since this is a pretty straightforward case, you can simply initialize the string and then concatenate onto it. You might want to add checks to ensure you don't go beyond you string's boundaries though.
strcpy(SITE_ROOT, "/var/www/html/");
strcat(SITE_ROOT, SITE_NAME);