So I am working on a project in C that requires that I pass pointers to a struct into functions. The project is structured as follows:
struct structName {
unsigned short thing2;
char thing1[];
};
void function_1(struct structName *s) {
strcpy(s->thing1, "Hello");
printf("Function 1\n%s\n\n", s->thing1); // prints correctly
}
void function_2(struct structName *s) {
// can read thing2's value correctly
// thing1 comes out as a series of arbitrary characters
// I'm guessing it's an address being cast to a string or something?
printf("Function 2\n%s\n\n", s->thing1); // prints arbitrary characters ('É·/¨')
}
int main() {
struct structName s;
function_1(&s);
printf("Main\n%s\n\n", s.thing1);
function_2(&s);
printf("Main 2\n%s\n\n", s.thing1);
}
This code outputs the following:
Function 1
Hello
Main
Hello
Function 2
É·/¨
Main 2
É·/¨
Obviously, the program has more than just what I've written here; this is just a simplified version; so if there's anything I should check that might be causing this let me know. In all honesty I reckon it's probably just a stupid rookie error I'm making somewhere.
[EDIT: Seems like s.thing1 is being mutated in some way in the call to function_2(), since the odd value is replicated in main() - I should point out that in my program the printf()s are located right before the function call and in the first line of the function, so there's no chance that it's being written to by anything I'm doing. I've updated the example code above to show this.]
Thanks in advance!
The structure contains a flexible member at its end, if you declare a static object with this type, the length of this member will be zero, so strcpy(s->thing1, "Hello"); will have undefined behavior.
You are supposed to allocate instances of this type of structure with enough extra space to handle whatever data you wish to store into the flexible array.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct pstring {
size_t length;
char data[];
} pstring;
pstring *allocate_pstring(const char *s) {
size_t length = strlen(s);
pstring *p = malloc(sizeof(*p) + length + 1);
if (p != NULL) {
p->length = length;
strcpy(p->data, s);
}
return p;
}
void free_pstring(pstring *p) {
free(p);
}
int main() {
pstring *p = allocate_pstring("Hello");
printf("Main\n%.*s\n\n", (int)p->length, p->data);
free_pstring(p);
return 0;
}
I need to read a word from main function and convert the characters in UCASE if the first character is LCASE and vice versa using the user defined function.I tried ways for returning the array from function but still I am lacking some core ideas. Please debug this program and explain the way it works.
#include <stdio.h>
#include <string.h>
int* low (char str)
{
int i;
for (i=1; i<strlen(str);i++)
{
if(str[i]<91)
{
str[i]=str[i]+32;
}
else
{
}
}
return &str;
}
int* high (char str[50])
{
int i;
for (i=0; i<strlen(str);i++)
{
if(str[i]>91)
{
str[i]=str[i]-32;
}
else
{
}
}
return &str;
}
void main()
{
char str[50];
char* strl;
printf("Enter any string....\n");
scanf("%s",str);
if (str[0]<91)
{
*strl=low(str);
}
else
{
*strl=high(str);
}
printf("Converted string is %s.",*strl);
}
There is already a problem here:
So if you are saying this code is perfect and you want us to debug it and explain how (on earth) this works, then here you go.
In function int* low (char str), you have if(str[i]<91). Thats a problem right there. str is a char received as an argument, and hence str[i] is a straight compile-time error.
Another one to deal with is the return statement.
You have a statement:
return &str;
which would return the address of str, which by the way is a char, whereas function low is supposed to return a pointer to an int.
The same is applicable to high function as well.
Suggestion: Leave aside this bad code and get a beginner level C programming book first. Read it and the try some codes out of it.
A few inputs for improvement: (Which you may not comprehend)
change
void main()
to
int main(void)
Why? Refer this legendary post: What should main() return in C and C++?
Secondly, int both functions you are using strlen() in loop which will always return a fixed value. So, instead of
for (i=0; i<strlen(str);i++)
I'd suggest,
size_t strlength = strlen(str);
for (i=0; i < strlength; i++)
You can try the code and method as below:
#include <stdio.h>
#include <string.h>
char* caseConverter (char *str)
{
int i;
for (i=0; i<strlen(str);i++)
{
if(str[i]>=65 && str[i]<=90)
{
str[i]=str[i]+32; //To lower case
}
else if((str[i]>=97 && str[i]<=122))
{
str[i]=str[i]-32; //To upper case
}
else
printf("%c is not an alphabet \n",str[i]);
}
return str;
}
void main()
{
char inputStr[50]= "Stubborn";
char* opStr= caseConverter(inputStr);
printf("Converted string is %s",opStr);
}
I am trying to write a small function to trim left spaces from a string, but I cannot get it right. In this version, I get the following error:
bus error: 10
Could anyone please explain to me what I am doing wrong? I am not looking so much for an alternative piece of code, but would like to understand the errors in my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void trim_string(char *);
int main(int argc, char *argv[]) {
char *temp = " I struggle with strings in C.\n";
trim_string(temp);
printf("%s", temp);
return 0;
}
void trim_string(char *string) {
char *string_trimmed = "";
int i=0, j=0;
while (isblank(string[i])) {
i++;
}
while (string[i] != '\0') {
string_trimmed[j] = string[i];
i++;
j++;
}
string_trimmed[j] = '\0';
strcpy(string, string_trimmed);
}
I have now found a workaround solution, shown below. But I am still not very clear about what I did wrong in the first place:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LENGTH 100
void trim_string(char [MAX_LENGTH]);
int main(int argc, char *argv[]) {
char temp[MAX_LENGTH] = " I struggle with strings in C.\n";
trim_string(temp);
printf("%s", temp);
return 0;
}
void trim_string(char string[MAX_LENGTH]) {
char string_trimmed[MAX_LENGTH];
int i=0, j=0;
while (isblank(string[i])) {
i++;
}
while (string[i] != '\0') {
string_trimmed[j] = string[i];
i++;
j++;
}
string_trimmed[j] = '\0';
printf("c\n");
strcpy(string, string_trimmed);
}
Both string and string_trimmed point to string literals, here in main:
char *temp = " I struggle with strings in C.\n";
^
|
This is a string literal
temp points to a string literal and the standard says you are not allowed to modify them.
In the function trim_string you are modifying a them which is undefined behavior of which a bus error is one possible result, although anything can happen.
string_trimmed either needs to be an array like this:
char string_trimmed[n] ;
where n is the size of your input using strlen(string) would probably make sense or dynamically allocated via malloc which you would need to free at the end of your function. The same things goes for your input from main, this would work as a substitute:
char temp[] = " I struggle with strings in C.\n";
For completeness sake, the draft C99 standard section 6.4.5 String literals paragraph 6 says (emphasis mine):
It is unspecified whether these arrays are distinct provided their elements have the
appropriate values. If the program attempts to modify such an array, the behavior is
undefined.
struct MemoryTag1;
typedef struct MemoryTag1{
char a[8]= {'+','0','2','6','.','5','EA','\r'}; // setpoint temperature value
char b[8]= {'-','0','2','4','.','5','EB','\r'};
char c[6]= {'+','0','2','0','EC','\r'};
}Memory1;
// This is a message structure which I want to transfer over the serial interface (RS232) and later convert into integer value. please guide me in this.
Your syntax is a bit off - try this:
// declare Memory1 struct type to hold data
typedef struct MemoryTag1 {
char a[9]; // setpoint temperature value
char b[9];
char c[7];
} Memory1;
// allocate and initialise a Memory1 struct
Memory1 m = { {'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'} };
Really, to be honest, I'd prefer more information. But it doesn't really matter. It only affects the method of output. If you were running this on an arduino, for instance, you could output to the serial ports as easily as:
Serial.begin(9600);
Serial.write('a');
etc, etc
As others have mentioned, there are situations in which you'd be better off using null-terminated strings. If however, you had a particular reason to do so, then I suppose you could;
#include <stdio.h>
typedef struct memoryTag1_t
{
char a[9]; // setpoint temperature value
char b[9];
char c[7];
} *pMemoryTag1_t;
typedef struct memoryTag2_t
{
char a[10]; // setpoint temperature value
char b[10];
char c[8];
} *pMemoryTag2_t;
void displayField1(char *field, int len)
{
for (int i=0; i<len; i++)
{
if (i!=0) printf(",");
printf("%c", field[i]);
}printf("\n");
}
void displayField2(char *field)
{
bool firstDone = false;
while (*field)
{
if (firstDone)
printf(",");
else
firstDone = true;
printf("%c", *field++);
}
printf("\n");
}
int main()
{
memoryTag1_t myMem1 =
{
{'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'}
};
memoryTag2_t myMem2 =
{
"+026.5EA\r",
"-024.5EB\r",
"+020EC\r"
};
displayField1(myMem1.a, sizeof(myMem1.a));
displayField1(myMem1.b, sizeof(myMem1.b));
displayField1(myMem1.c, sizeof(myMem1.c));
displayField2(myMem2.a);
displayField2(myMem2.b);
displayField2(myMem2.c);
}
Output:
(Don't forget there's a \r printed 'after' the last comma in each line)
+,0,2,6,.,5,E,A,
-,0,2,4,.,5,E,B,
+,0,2,0,E,C,
+,0,2,6,.,5,E,A,
-,0,2,4,.,5,E,B,
+,0,2,0,E,C,
you can not declare struct in C in this way:
it should be
typedef struct MemoryTag1{
char a[9];
char b[9];
char c[7];
}Memory1;
you can set value in the declaration of an object of this structure:
Memory1 test = {
{'+','0','2','6','.','5','E','A','\r'},
{'-','0','2','4','.','5','E','B','\r'},
{'+','0','2','0','E','C','\r'}
};
If you use this bloc in each initiation of a Memory1 object so you can use macro to make it easier:
#define INIT_MEMORYTAG1 {\
{'+','0','2','6','.','5','E','A','\r'},\
{'-','0','2','4','.','5','E','B','\r'},\
{'+','0','2','0','EC','\r'}\
}
and then in your declaration of a Memory1 object:
Memory1 test = INIT_MEMORYTAG1;
BTW: You can not put 'EA', 'EB', 'EC' like a 1 charachter you have to separate them to:
'E','A', 'E','B', 'E','C' and so you have to update your char array sizes in the struct definition
That is really not C syntax.
You can't have initializers in declarations of types, that doesn't have any meaning.
You need to do it like this, to build the message:
typedef struct {
char a[10];
char b[10];
char c[8];
} Memory1;
int main(void)
{
Memory1 m1;
strcpy(m1.a, "+026.5EA\r");
strcpy(m1.b, "-024.5EB\r");
strcpy(m1.c, "+020EC\r");
return 0;
}
Note that the above will build proper C strings in the fields of the message, i.e. there will be 0-characters acting as terminators. The sizes were too small, so I changed that.
It's trivial to ignore the terminator characters if you need to send this over some format that doesn't allow them; send each field separately.
Converting one of the fields back into integers could be done using sscanf(), for instance.
First, my objective with this code: take in a sentence into a C string. Iterate through the sentence and see how many instances of a particular letter occur.
This code is working somewhat but not giving the right number? Not sure why:
#include <stdio.h>
#include <string.h>
int tracker=0;
int letterCount (char *sentence)
{
int s=strlen(sentence);
int i=0;
for (i=0; i<s; i++){
if (sentence[i]=='h') {
tracker++;
}
}
return tracker;
}
int main(int argc, const char * argv[])
{
char *string="Hi there, what's going on? How's it going?";
letterCount(string);
printf("this sentensce has %i H's", tracker);
return 0;
}
The output I'm getting:
this sentensce has 2 H's
Not quite right. Any ideas?
This is the correct code if you mean case insensitive H:
#include <stdio.h>
#include <string.h>
int tracker=0;
int letterCount (char *sentence)
{
int s=strlen(sentence);
int i=0;
for (i=0; i<s; i++){
if (sentence[i]=='h' || sentence[i]=='H') { //'h' is not the same as 'H'
tracker++;
}
}
return tracker;
}
int main(int argc, const char * argv[])
{
char *string="Hi there, what's going on? How's it going?";
letterCount(string);
printf("this sentensce has %i H's", tracker);
return 0;
}
You have just mispelled small and the capital letter in your code.
Remember, the C language is case sensitive!
Although your label talks about the number of Hs, your letterCount looks for hs instead -- and it looks to me like the input you've provided does have two instances of lower-case h, just as it says.
If you want to count them together, you might consider filtering each input with tolower or toupper before checking what you have.
That number looks correct to me: you have 2 'h' characters in that sentence. If you want to count the 'H' characters as well, then you need a separate check.
size_t letterCount(const char* sentence, char c)
{
size_t count = 0;
while(sentence)
{
count += (*sentence == c);
++sentence;
}
return count;
}
What do we see here?
You can't have negative count, so use an unsigned type like size_t
sentence shouldn't be modified, so it should be const
pass in the char you want to match
sentence is a pointer, if it is null you are done. Don't need to call strlen.
sentence is a pointer, the actual pointer is pass by value, so you can modify it (see the increment, no need to make an extra variable)
boolean operators return 1 or 0, so no need to use the if. (Although, I haven't looked at the assembly to see if an if branch or an add 0 is cheaper. YMMV)