How do you use a string array as a parameter in C? If I were to write a function with signature:
Guess i didnt explain myself very well... I'll post the code that i'm trying to get to work.
int format_parameters(char* str) {
char local_str[201] = "";
int i = 0;
int j = 0;
int flip = 0;
while(str[i]) {
if((str[i] == '"') && (flip == 0)) flip = 1;//Sentence allowed
else if((str[i] == '"') && (flip == 1)) flip = 0;//Sentence not allowed
if(flip == 1) append_char(local_str, str[i]);
//check if space
else if(flip == 0) {
int c = str[i];
if(!isspace(c)) append_char(local_str, str[i]);
else {
if((strlen(local_str) > 0) && (j < 4)) {
//local-str copied to param[j] here
//printf("j = %d %s\n",j,local_str);
local_str[0] = '\0';
j++;
}
}
}
i++;
}
//Add \0 to param
return flip;
}//end format_parameters
void append_char(char* str, char c) {
int len = strlen(str);
str[len] = c;
str[len+1] = '\0';
}//end append_char
int main() {
char str[200];
//str filled with stuff...
int x = format_parameters(str);
}
There should be a second (and third?) parameter in format_parameterssignature, a char* param[5] which should be readable from main.
Does this work?
#include <string.h>
#include <assert.h>
#include <stdio.h>
int format_parameters(char *str, char *param[], size_t nparam)
{
char **next = param;
char **end = param + nparam;
char *data = str;
assert(str != 0 && param != 0 && nparam != 0);
while (next < end && *data != '\0')
{
*next++ = data;
data = strchr(data, ' '); // Choose your own splitting criterion
if (data == 0)
break;
*data++ = '\0';
}
return(next - param);
}
int main(void)
{
char str[] = "a b c d";
char *param[5];
int nvals = format_parameters(str, param, 5);
int i;
for (i = 0; i < nvals; i++)
printf("Param %d: <<%s>>\n", i+1, param[i]);
return 0;
}
The return value is the number of parameters found. If you pass an empty string, that would be 0. Beware leading, trailing and repeated blanks; the code works - but maybe not as you want it to.
This is entirely about memory allocation.
If you allocate static memory for param before the function is called, the memory will exist in that scope.
Otherwise take a look at dynamic allocation, it will exist until you tell it to go away.
You have to create the char* param[] array outside the function and just pass it as a parameter:
int paramCount = countParameters(str); // you have to create this function
char* param[] = malloc(paramCount * sizeof(char*));
format_parameters(str, param);
and inside the function:
int format_parameters(char* str, char* param[])
{
int currentParamIndex = 0;
..........
//TODO: check if currentParamIndex < paramCount
char* currentParam = str + currentParamStart; // currentParamStart is the start index of the parameter in the str containing all parameters
param[currentParamIndex] = currentParam;
currentParamIndex++;
.............
}
And in order to write safe code you have to pass also the paramCount as a parameter to format_parameters so the function will not access an element out of the bounds of the array.
Or maybe you should just use getopt?
As Jonatahan pointed out, you need more parameters:
int format_parameters(char* strInput, char* paramOutput[], size_t cbMaxParams );
// return value is actual number of parameter strings in paramOutput
paramOutput is an array of pointers. So the caller has to provide an array of pointers and the called function has to allocate memory for the strings and set the pointers in the array:
// main:
#define SIZE 20
char * params[SIZE];
int result = format_parameters( szInput, params, SIZE );
// after use go through params and free all pointers
// function:
int format_parameters(char* strInput, char* paramOutput[], size_t cbMaxParams )
{
// ...
for( size_t i=0; (i<cbMaxParams) && (!noMoreParams); i++ )
{
// ...
paramOutput[i] = (char *)malloc( xxxx );
// ...
}
// ...
}
Related
char * deleteChars = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r"
I have this and i'm trying to remove any of these from a given char*. I'm not sure how I would go about comparing a char* to it.
For example if the char* is equal to "hello," how would I go about removing that comma with my deleteChars?
So far I have
void removeChar(char*p, char*delim){
char*holder = p;
while(*p){
if(!(*p==*delim++)){
*holder++=*p;
p++;
}
}
*holder = '\0';
A simple one-by-one approach:
You can use strchr to decide if the character is present in the deletion set. You then assign back into the buffer at the next unassigned position, only if not a filtered character.
It might be easier to understand this using two indices, instead of using pointer arithmetic.
#include <stdio.h>
#include <string.h>
void remove_characters(char *from, const char *set)
{
size_t i = 0, j = 0;
while (from[i]) {
if (!strchr(set, from[i]))
from[j++] = from[i];
i++;
}
from[j] = 0;
}
int main(void) {
const char *del = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r";
char buf[] = "hello, world!";
remove_characters(buf, del);
puts(buf);
}
stdout:
hello world
If you've several delimiters/characters to ignore, it's better to use a look-up table.
void remove_chars (char* str, const char* delims)
{
if (!str || !delims) return;
char* ans = str;
int dlt[256] = {0};
while (*delims)
dlt[(unsigned char)*delims++] = 1;
while (*str) {
if (dlt[(unsigned char)*str])
++str; // skip it
else //if (str != ans)
*ans++ = *str++;
}
*ans = '\0';
}
You could do a double loop, but depending on what you want to treat, it might not be ideal. And since you are FOR SURE shrinking the string you don't need to malloc (provided it was already malloced). I'd initialize a table like this.
#include <string.h>
...
char del[256];
memset(del, 0, 256 * sizeof(char));
for (int i = 0; deleteChars[i]; i++) del[deleteChars[i]] = 1;
Then in a function:
void delChars(char *del, char *string) {
int i, offset;
for (i = 0, offset = 0; string[i]; i++) {
string[i - offset] = string[i];
if (del[string[i]]) offset++;
}
string[i - offset] = 0;
}
This will not work on string literals (that you initialize with char* x = "") though because you'd end up writing in program memory, and probably segfault. I'm sure you can tweak it if that's your need. (Just do something like char *newString = malloc(strlen(string) + 1); newString[i - offset] = string[i])
Apply strchr(delim, p[i]) to each element in p[].
Let us take advantage that strchr(delim, 0) always returns a non-NULL pointer to eliminate the the null character test for every interrelation.
void removeChar(char *p, char *delim) {
size_t out = 0;
for (size_t in; /* empty */; in++) {
// p[in] in the delim set?
if (strchr(delim, p[in])) {
if (p[in] == '\0') {
break;
}
} else {
p[out++] = p[in];
}
}
p[out] = '\0';
}
Variation on #Oka good answer.
it is better way - return the string without needless characters
#include <string.h>
char * remove_chars(char * str, const char * delim) {
for ( char * p = strpbrk(str, delim); p; p = strpbrk(p, delim) )
memmove(p, p + 1, strlen(p));
return str;
}
This code has a problem in the struct data members. When I call a function like Evaluator() function the token[0].value will corrupt or will turn into a garbage. I tried to allocate a memory for the value data member but still no luck. I also tried to allocate a memory for the struct itself but still it doesn't work. Can someone help me with this?
struct tokens
{
char *value;
char type = ' ';
};
void inputComponent(char input_string[size])
printf("\n> ");
scanf("%[^\n]s", input_string);
}
int processingComponent(char *input_string, int *result)
{
int error_flag = 0;
tokens token[size];
error_flag = Parser(input_string, token);
if (error_flag == 0)
error_flag = Evaluator(result, token);
return error_flag;
}
int Parser(char *input_string, struct tokens token[size])
{
char valid_operators[size] = { "+-*/%" };
char temp = ' ';
char number_string[size] = { NULL };
int counter = 0;
int countStruct = 0;
int tempCounter = 0;
do
{
temp = input_string[counter];
if (isdigit(temp))
{
number_string[tempCounter] = temp;
tempCounter++;
}
else if (strpbrk(input_string, valid_operators))
{
if (temp == '%')
return (-1);
else if (number_string != NULL)
{
char tempNum[size] = { NULL };
strcpy(tempNum, number_string);
token[countStruct].value = tempNum;
token[countStruct].type = 'N';
countStruct++;
tempCounter = 0;
for (int x = 0; number_string[x] != NULL; x++)
number_string[x] = NULL;
}
}
else
return (-2);
counter++;
} while (counter < strlen(input_string));
return 0;
}
int Evaluator(int *result, struct tokens token[size])
{
for(int x = 0; x < 3; x++) //value of token[0].value = ÌÌÌÌÌÌÌÌÌÌÌÌ
printf("%s", token[x].value);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
char input_string[size] = { NULL };
int result = 0;
int error_flag = 0;
inputComponent(input_string);
error_flag = processingComponent(input_string, &result);
_getch();
_getch();
return 0;
}
For starters, when you pass an array of tokens to the Parser and Evaluator functions, you are passing the variables by value. The token array is not actually changed after calling Parser():
`
int Parser(char *input_string, struct tokens myArray[size])
{
//modifying myArray will not modify the array that was actually passed
//to this function from the processingComponent() function.
}
`
First change your Parser and Evaluator functions like so:
#define ARRAY_SIZE 100 //an arbitrary size
int Parser( char* input_string, struct token* tokenArray )
{
//access each element as so:
//tokenArray[0];
//tokenArray[ ARRAY_SIZE - 1 ];
}
int Evaluator(int *result, struct token* tokenArray )
{
for(int x = 0; x < ARRAY_SIZE; x++)
printf("%s", tokenArray[x].value);
return 0;
}
Then call the Parser() function as so:
EDIT: Since it is a good idea to allocate and free memory within the same function (so that you don't end up with spaghetti code), this would be a better solution:
int processingComponent(char *input_string, int *result)
{
int error_flag = 0;
token tokenArray[ARRAY_SIZE];
//allocate memory here
for( int i = 0; i < ARRAY_SIZE; i++ ) {
tokenArray[i].value = (char*)malloc( sizeof(char) * MAX_STRING_LENGTH);
}
error_flag = Parser(input_string, &tokenArray[0]);
if (error_flag == 0)
error_flag = Evaluator(result, &tokenArray[0]);
//free memory here before the token array goes out of scope:
for( int i = 0; i < ARRAY_SIZE; i++ ) {
free( tokenArray[i].value );
tokenArray[i].value = NULL;
}
return error_flag;
}
When you allocate memory for your token string, it needs to be dynamically allocated using malloc() and deleted using free().
Replace this:
strcpy(tempNum, number_string);
token[countStruct].value = tempNum;
//with:
#define MAX_STRING_LENGTH 255 //arbitrary
//Memory has already been allocated, so just copy the string into the token
strncpy( token[countStruct].value, number_string, MAX_STRING_LENGTH - 1 );
token[countStruct].value[MAX_STRING_LENGTH-1] = NULL;
You don't appear to be allocating any storage for token[].value. You set it equal to tempNum, but that goes out of scope in the inner block in Parser(). I would say that anything this code does is undefined because you're accessing memory that was deallocated when Parser() returned.
Precautions with Structures
I have added a text file, which contains your running code with instructions.
one important thing you can not assign any thing directly into structure, because declaration of structure reserve no space.
Why did you do such a hectic job to achieve something like this..
input :12+3-1/7
output:12317
Click this link to get your running c code
I have two string shown below:
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
In a part of the program I used the following code where it increments the pointers for both strings to point to the next characters.
ch_A = text_to_compare[i++];
ch_B = dictionary[j++];
Why is pointer j being incremented but pointer i is remaining as it was?
Thanks in advance.
EDIT: Below is the full code. The aim of this project is to compare a string with a list of words. Integer i is not incrementing only after the program enters the else statement.
#include <string.h>
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
int bring_characters(char pdata *, char pdata *, char ch_A, char ch_B, char i,
char j);
void main(void) {
unsigned char ch_A;
unsigned char ch_B;
unsigned char i = 0;
unsigned char j = 0;
char pdata N1;
char pdata N2;
int result;
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j];
result = bring_characters(&N1, &N2, ch_A, ch_B, i, j);
if (result == 0) {
while (1)
;
}
else {
while (1)
;
}
while (1)
;
}
int bring_characters(char pdata *N1, char pdata *N2, char ch_A, char ch_B,
char i, char j) {
do {
if (ch_A == ch_B) {
ch_A = text_to_compare[i++]; // take a caharacter from the text
ch_B = dictionary[j++];
if ((ch_A == '\0') && ((ch_B == ',') || (ch_B == '.'))) {
while (1)
; // load idata-------------------------------------------------------------------------------------------------
}
}
else {
i = 0; // refresh pointer
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j++];
}
} while (ch_B != '.');
return (0);
}
Whew, there's a lot going on here! Now that you've added the full code it looks like in your attempt to move on to the next word you have prevented yourself from moving on.. you'll need to do some major revisions to get this guy working.
The first thing you need to do is figure out how you would do this on paper, then step by step try to reproduce that in your code.
Here's a function to kickstart you:
int find_next_match(char toFind, int startingPosition, char* mainString){
int counter = startingPosition;
char buf = mainString[counter];
while(buf != NULL){
if (buf == toFind){
return counter;
}
counter++;
buf = mainString[counter];
}
return -1; //error
}
You can use something like this to find the next instance of the first character in your string, then you can implement a loop to determine if that is a match.
Good luck, you can do it!
Keep getting an error on my return ret before the main () class (end of process request)
buddy.c: In function `process_request':
buddy.c:89: warning: function returns address of local variable
Error I receive , what I'm trying to do is print the results I get from my process_request to my print near the end of my main() function, help?
//used a flag
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define F_SIZE 2
#define A_SIZE 2
#define BUDDY_SIZE 4*1024 // in bytes
// compile using gcc-o buddy buddy.c -lm
// block information
struct block_info
{
char AF_flag; // flag
int data; // data in the block
};
typedef struct block_info block;
block buddy_block[BUDDY_SIZE]; // entire buddy system to be used in this array
int block_count = 0; // number of blocks in buddy_block
int get_block_size(int num)
{
int i = 0;
for (i = 0; num < pow(2.0, (double)i); ++i);
return (int)(pow(2.0, (double)i));
}
char *process_request(char *s, int len)
{
block b;
block n;
int i, j, count, block_size = 0;
int first_buddy_size = 0;
int second_buddy_size = 0;
char ret[BUDDY_SIZE] = { 0 };
char *response[BUDDY_SIZE] = { 0 };
if (!s)
return NULL;
first_buddy_size = buddy_block[0].data;
second_buddy_size = buddy_block[1].data;
block_size = get_block_size(atoi(s));
// get the matching FREE block in the power of 2
if (*s == 'A')
{ // Allocation request
int i = 0;
char *buff = NULL;
// split the block
char strf[F_SIZE] = { 0 };
char stra[A_SIZE] = { 0 };
strf[0] = 'F';
stra[0] = 'A';
for (i = 0; block_size <= first_buddy_size / 2; ++i)
{
first_buddy_size /= 2;
sprintf(buff, "%d", first_buddy_size);
response[i] = strcat(strf, buff);
}
sprintf(buff, "%d", block_size);
response[i] = strcat(stra, buff);
// update the array
count = i;
for (i = 0, j = count; j; --j, ++i)
{
char *str = response[j];
buddy_block[i].AF_flag = *str++;
while (*str)
buddy_block[i].data = *str;
}
}
else if (*s == 'F')
{ // Free request
for (i = 1; i < block_count; ++i)
{ // traversing through the array
if (buddy_block[i].data = block_size)
{ // b.AF_flag = 'B';
i << 1;
}
}
}
// update array
count = i;
for (i = 0, j = count; j; --j, ++i)
{
char *str = response[j];
buddy_block[i].AF_flag = *str++;
while (*str)
buddy_block[i].data = *str;
}
return ret; // ------------error: warning functions returns address
// of local variable----------
}
int main(int argc)
{
block t;
int i;
char ch;
char *ret = NULL;
char line[20];
t.AF_flag = 'X'; // some junk means memory block not even accessed
t.data = 0;
for (i = 0; i < BUDDY_SIZE; i++)
buddy_block[i] = t; // initialize with 0 bytes and no information about
// Allocation/Free
// initially there is only one Free block of 4K bytes
t.AF_flag = 'F';
t.data = BUDDY_SIZE;
buddy_block[0] = t; // started the buddy block to 4096 bytes, all free to be
// allocated
++block_count;
while (1)
{
// get user input
char request[5] = { 0 }; // 'F4096' or 'A4096', max 5 chars
int correct_input = 0;
char ch;
for (i = 0, ch = 'X'; ch != '\n'; ++i)
{
ch = getchar();
if ((i == 0) && (ch != 'A' || ch != 'F'))
{
printf("Illegal token!!! : should be A or F");
correct_input = 0;
break;
}
if (ch < '0' && ch > '9')
{ // illegal code
printf("Illegal token!!! : should be 0 and 9");
}
correct_input = 1;
request[i] = ch;
}
if (correct_input)
{
// process user input
ret = process_request(request, sizeof(request));
printf("%d", ret); // [512](512A)(128A)(128F)(256F)(1024F)(2048F)
// //fprintf(stderr, "I am in stderr");
fflush(stdout);
}
}
return 0;
}
You have allocated ret on the stack. Although it is not forbidden to return an address to that the stack will be reused by any function that is called afterwards thus overwriting whatever was at that address.
You may want to consider moving this data onto the caller's stack or into dynamic memory.
char * foo() {
char string[] = "Hello world\n";
return string;
}
int main () {
printf("%s", foo());
}
Will most likely not print "Hello World!".
One right way would be:
void foo(char * buffer) {
memcpy(buffer, "Hello world\n", sizeof("Hello world\n"));
}
int main () {
char buffer[100];
foo(&buffer);
printf("%s", buffer);
}
Or with dynamic memory (prone to memory leaks):
char * foo() {
char * string = malloc(sizeof("Hello world\n"));
memcpy(string, "Hello world\n", sizeof("Hello world\n"));
return string;
}
int main () {
char * string = foo();
printf("%s", string);
free(string);
}
It means exactly what it says. You are doing
char* process_request(char*s, int len) {
...
char ret[BUDDY_SIZE] = {0};
...
return ret;
}
ret is an address to a memory location. The issue is that such memory location points to a local variable. A local variable lies in the stack, and its memory may be (probably will) reused for other variables when you call new functions.
To avoid that, return a pointer to a memory location that has been dynamically allocated (that means malloc and friends).
You are returning a local pointer from a function and that is an undefined value.
char ret[BUDDY_SIZE] = {0};
SO, your compiler is throwing that error. Assign your pointer dynamically and the error should go away.
Im trying to copy part of a string to another string using pointers. My resulting string starts to copy at the correct place though it doesn't stop after exceeding the count. Also the string isn't copy from the source string rather than from the result parameter
#include <stdio.h>
char *getSub(const char *orig, int start, int count, char *res);
int main(void)
{
const char orig[] = "one two three";
char res[] = "123456789012345678";
printf("%s\n",getSub(orig, 4, 3, res));
return 0;
}
char *getSub(const char *orig, int start, int count, char *res)
{
const char *sCopy = orig;
while (*orig)
{
if (start >= (orig - sCopy)) && (res-sCopy < count))
{
*res++ = *orig++;
}
else
*orig++;
}
return res;
}
The big mistake is that you're calculating the difference of two unrelated pointers, res - sCopy (I suppose sourceCopy is also sCopy in the real code, or the other way round). Calculating the difference of pointers is only meaningful if both pointers point into (or one past the end of) the same array. As written, whether anything gets copied at all depends on the arbitrary locations of the two arrays.
if (start >= (orig - sourceCopy)) && (res-sCopy < c))
{
*res++ = *orig++;
}
else
*orig++;
anyway, that doesn't count how many characters are copied if any are copied at all.
Another mistake is that you don't 0-terminate the copy.
A correct implementation would be
char *getSub(const char *orig, int start, int count, char *res)
{
char *from = orig, *to = res;
// check whether the starting position is within orig
for( ; start > 0; --start, ++from)
{
if (*from == 0)
{
res[0] = 0;
return res;
}
}
// copy up to count characters from from to to
for( ; count > 0 && *from; --count)
{
*to++ = *from++;
}
// 0-terminate
*to = 0;
// return start of copy, change to return to if end should be returned
return res;
}
There are at least two problems with your code.
res - sCopy makes no sense because they are pointing at different objects.
You haven't null-terminated the destination string.
#include <string.h>
char *getSub(const char *orig, int start, int count, char *res){
int i,j,len = strlen(orig), limit = start + count;
if(res == NULL) return NULL;
if(start >= len || start < 0 || orig == NULL){
*res = '\0';
return res;
}
for(j=0,i=start;i<len && i < limit;++i){
res[j++]=orig[i];
}
res[j]='\0';
return res;
}