I'm trying to make a simple code that converts one type of data into another. I use strtok to extract one part of the data and then I run a long serial of if conditions to find the right output. However, when the correct output is found and written in the variable currentNote, it also seems to overwrite the variable comma for a reason I can't figure out. Here is the problematic part of the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char sequence[] = "c1[M],c1[M],d3[L],c3[M],b2[M],(#A-2)[IKN],(#A-1)[L]";
char copy[] = "";
char *comma;
char currentNote[4] = "";
strcpy(copy, sequence);
comma = strtok(copy, ",");
if(strstr(comma, "c1") != 0) //c1
{
printf("%s\n\n", comma); //Here ...
strcpy(currentNote, "C5 ");
printf("%s\n\n", comma);
}
return 0;
}
And here's the outcome :
c1[M]
cC5
No need to say that strcpy(currentNote, "C5 "); is causing it. I don't know why though, I thought it would return c1[M] like I would like it to do. After some more experimentation it turns out that the secondprintf("%s\n\n", comma); will always return the first character of sequence followed by C5. I hope someone can find out, it would be very great.
You are calling
strcpy(copy, sequence) while copy is a 1 element length array. You need to define it by giving it sufficient size. Your code as is, is simply a UB. Redefine it like
char copy[100];
Or allocate sufficient memory to it dynamically using malloc.
Related
So I suck with functions and need to debug this. Im pretty sure the function ToPigLating does its job well at converting. However I just need help calling the function ToPigLatin inside of my main function. But when I try doing that I just get a bunch of error codes.
#include <stdlib.h>
#include <string.h>
#define LEN 32
char* ToPigLatin(char* word[LEN]){
char word[LEN];
char translation [LEN];
char temp [LEN];
int i, j;
while ((scanf ("%s", word)) != '\0') {
strcpy (translation, word);
//just pretend I have all the work to convert it in here.
} // while
}
int main(){
printf("Enter 5 words: ");
scanf("%s", word);
ToPigLatin();
}```
Roughly, variables only exist within the function they're declared in. The word in ToPigLatin exists only within ToPigLatin. It is not available in main. This lets us write functions without worrying about all the rest of the code.
You need to declare a different variable in main, it can also be called word, to store the input and then pass that into ToPigLatin.
Let's illustrate with something simpler, a function which doubles its input.
int times_two(int number) {
return number * 2;
}
We need to give times_two a number.
int main() {
// This is different from "number" in times_two.
int number = 42;
// We have to pass its value into time_two.
int doubled = times_two(number);
printf("%d doubled is %d\n", number, doubled);
}
Your case is a bit more complicated because you're working with input and memory allocation and arrays. I'd suggest just focusing on arrays and function calls for now. No scanf. No strcpy.
For example, here's a function to print an array of words.
#include <stdio.h>
// Arrays in C don't store their size, the size must be given.
void printWords(const char *words[], size_t num_words) {
for( int i = 0; i < num_words; i++ ) {
printf("word[%d] is %s.\n", i, words[i]);
}
}
int main(){
// This "words" variable is distinct from the one in printWords.
const char *words[] = {"up", "down", "left", "right"};
// It must be passed into printWords along with its size.
printWords(words, 4);
}
ToPigLatingToPigLating function expects to have a parameter like ToPigLating("MyParameter");
Hello there icecolddash.
First things first, there are some concepts missing. In main section:
scanf("%s", word);
You're probably trying to read a string format and store in word variable.
In this case, you should have it on your declaration scope. After some adjustment, it will look like this:
int main(){
char word[LEN];
As you defined LEN with 32 bytes maximum, your program will not be allowed to read bigger strings.
You're also using standard input and output funcitions as printf, and so you should ever include stdio.h, thats the header which cointains those prototypes already declared, avoiding 'implicit declaration' compiling warnings.
Next issue is how you're declaring your translation function, so we have to think about it:
char* ToPigLatin(char* word[LEN])
In this case, what you wrote:
ToPigLatin is a funcion that returns a char pointer, which means you want your function to probably return a string. If it makes sense to you, no problem at all. Although we got some real problem with the parameter char* word[LEN].
Declaring your variable like this, assume that you're passing an array of strings as a parameter. If I got it right, you want to read all five words in main section and translate each one of them.
In this case I suggest some changes in main function, for example :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 32
#define MAX_WORDS 5
char *globalname = "translated";
char* ToPigLatin(char* word){
char *translation = NULL;
//Translation work here.
if ( !strcmp(word, "icecolddash") ){
return NULL;
}
translation = globalname;
return translation;
}
int main(){
char word[LEN];
char *translatedword;
int i;
printf("Enter 5 words: \n");
for ( i=0; i < MAX_WORDS; i++ ){
fgets(word, sizeof(word), stdin);
strtok(word, "\n"); // Just in case you're using a keyboard as input.
translatedword = ToPigLatin(word);
if ( translatedword != NULL ){
//Do something with your translation
//I'll just print it out as an example
printf("%s\n", translatedword);
continue;
}
// Generic couldn't translate message
printf("Sorry, I know nothing about %s\n", word);
}
return 0;
}
The above code translate every word in a fixed word "translated".
In case of reading the exact input "icecolddash", the program will output a generic error message, simulating some problem on translation process.
I hope this help you out with your studies.
There are a few things that I see.
#include <stdio.h>
#include <stdlib.h>
char* ToPigLatin(char* word){
printf(word);
return word;
}
int main(){
printf("Enter 5 words: ");
// declare the variable read into by scanf
char * word = NULL;
scanf("%s", word);
//Pass the variable into the function
ToPigLatin(word);
// Make sure you return an int from main()
return 0;
}
I left some comments in the code with some specific details.
However, the main thing that I would like to call out is the style of the way you're writing your code. Always try to write small, testable chunks and build your way up slowly. Try to get your code to compile. ALWAYS. If you can't run your code, you can't test it to figure out what you need to do.
As for the char ** comment you left on lewis's post, here is some reading you may find useful in building up your intuition:
https://www.tutorialspoint.com/what-does-dereferencing-a-pointer-mean-in-c-cplusplus
Happy coding!
I'm working on the following homework problem:
Given the first name and last name as parameters, write the code of
the function createFBlink(). The functions returns a facebook link
which serves as an alternate email of the facebook user. The variable
holding the facebook link should contain the minimum number of bytes
required to store the string representing the facebook link. If there
is no first name or last name, the function returns NULL.
For example, if firstname = tzuyu and lastname = chou, the
facebook link is chou.tzuyu#facebook.com.
(See the original problem statement here.)
I've been trying to return a string from createFBlink into main. I've tried multiple methods such as turning char into static but I keep getting errors that I don't understand because I don't have a lot of experience with C.
I've had the best luck with using malloc, but I've come across a problem wherein if ever there are parameters to the function I'm sending from main, I end up with a crash after the input. Here's my code so far:
#include <string.h>
#include <conio.h.>
#include <stdio.h>
#include <stdlib.h>
char *createFBlink(char *firstname , char *lastname) ;
int main(void)
{
char firstname[24] , lastname[24], fblink[24] ;
printf("Enter first name: ");
scanf("%s", firstname);
firstname[strlen(firstname)] = '\0';
printf("\n Enter last name: ");
scanf("%s", lastname);
lastname[strlen(lastname)] = '\0';
*fblink = createFBlink(firstname, lastname);
if(*firstname == '\0'){
printf("no facebook link generated");
}else{
printf("%s", *fblink);
}
getch();
return 0;
}
char * createFBlink(char *firstname , char *lastname)
{
int check1 = strlen(firstname) , check2 = strlen(lastname), num = check1+check2;
char link = (char*) malloc(sizeof(char) * num);
if(check1 == 0 || check2 == 0){
*firstname = '\0' ;
}else{
strcat(*lastname, ".");
strcat(*lastname, firstname);
strcat(*lastname, "#facebook.com");
strcpy(link , *lastname);
return link;
}
}
*link = (char *) malloc(24);
This is incorrect, it should be
link = (char *) malloc(24);
*link (the same as link[0]) is the first character of the string pointed by link, that assignment is just overwriting the character, not changing the pointer.
The following is also incorrect:
*fblink = createFBlink(firstname, lastname);
This:
strcat(*lastname, ...);
is incorrect in the same way. You are getting the first character of the string pointed by lastname, converting it to a pointer and passing this (obviously invalid) pointer to strcat. This is the most likely reason of the crash.
Also, 24 characters may not be enough to hold the concatenated string.
Try to read a book about working with pointers in C, trying to understand them via trial-and-error is probably not the most effective way.
When working with strings, you need to understand the types you are using.
This is a fixed area in memory, of fixed size.
char buffer [24];
This is a dynamically allocated buffer that must be freed
char* szBuffer = malloc(24);
free(szBuffer)
Instead of doing that correctly, your createFBlink does malloc twice, and free zero times.
If you return a malloc'ed buffer from a function, you still must free it.
char * result = createFBlink(stuff);
free(result);
Since the types are different, you would need to use another function to move the string data from one to the other.
char * result = createFBlink(stuff);
strcpy(fblink, result, sizeof(fblink));
free(result);
And then you have additional risk from writing outside the allocated space. Let's try a made-up name with some common names.
firstname "Richard"
lastname "Hernandez"
returned string "Hernandez.Richard#facebook.com"
Oh look, 31 characters in a 24 character string. We just overwrite something, somewhere on your computer. Literally anything could happen, now.
So you have all kinds of risk. You have to match malloc with free. You have to keep track of the size. All of this is considered to be VERY BAD c++ style. The std::string class is highly recommended for this. You want your string class to take care of all the resource management, so you can't mess it up while you are using it.
std::string CreateFacebookLink (const std::string &firstname, const std::string &lastname){
return firstname + "." + lastname + "#facebook.com";
}
std::string strFacebookLink (CreateFacebookLink("Richard", "Hernandez"));
So I'm new to C and the whole string manipulation thing, but I can't seem to get strtok() to work. It seems everywhere everyone has the same template for strtok being:
char* tok = strtok(source,delim);
do
{
{code}
tok=strtok(NULL,delim);
}while(tok!=NULL);
So I try to do this with the delimiter being the space key, and it seems that strtok() no only reads NULL after the first run (the first entry into the while/do-while) no matter how big the string, but it also seems to wreck the source, turning the source string into the same thing as tok.
Here is a snippet of my code:
char* str;
scanf("%ms",&str);
char* copy = malloc(sizeof(str));
strcpy(copy,str);
char* tok = strtok(copy," ");
if(strcasecmp(tok,"insert"))
{
printf(str);
printf(copy);
printf(tok);
}
Then, here is some output for the input "insert a b c d e f g"
aaabbbcccdddeeefffggg
"Insert" seems to disappear completely, which I think is the fault of strcasecmp(). Also, I would like to note that I realize strcasecmp() seems to all-lower-case my source string, and I do not mind. Anyhoo, input "insert insert insert" yields absolutely nothing in output. It's as if those functions just eat up the word "insert" no matter how many times it is present. I may* end up just using some of the C functions that read the string char by char but I would like to avoid this if possible. Thanks a million guys, i appreciate the help.
With the second snippet of code you have five problems: The first is that your format for the scanf function is non-standard, what's the 'm' supposed to do? (See e.g. here for a good reference of the standard function.)
The second problem is that you use the address-of operator on a pointer, which means that you pass a pointer to a pointer to a char (e.g. char**) to the scanf function. As you know, the scanf function want its arguments as pointers, but since strings (either in pointer to character form, or array form) already are pointer you don't have to use the address-of operator for string arguments.
The third problem, once you fix the previous problem, is that the pointer str is uninitialized. You have to remember that uninitialized local variables are truly uninitialized, and their values are indeterminate. In reality, it means that their values will be seemingly random. So str will point to some "random" memory.
The fourth problem is with the malloc call, where you use the sizeof operator on a pointer. This will return the size of the pointer and not what it points to.
The fifth problem, is that when you do strtok on the pointer copy the contents of the memory pointed to by copy is uninitialized. You allocate memory for it (typically 4 or 8 bytes depending on you're on a 32 or 64 bit platform, see the fourth problem) but you never initialize it.
So, five problems in only four lines of code. That's pretty good! ;)
It looks like you're trying to print space delimited tokens following the word "insert" 3 times. Does this do what you want?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char str[BUFSIZ] = {0};
char *copy;
char *tok;
int i;
// safely read a string and chop off any trailing newline
if(fgets(str, sizeof(str), stdin)) {
int n = strlen(str);
if(n && str[n-1] == '\n')
str[n-1] = '\0';
}
// copy the string so we can trash it with strtok
copy = strdup(str);
// look for the first space-delimited token
tok = strtok(copy, " ");
// check that we found a token and that it is equal to "insert"
if(tok && strcasecmp(tok, "insert") == 0) {
// iterate over all remaining space-delimited tokens
while((tok = strtok(NULL, " "))) {
// print the token 3 times
for(i = 0; i < 3; i++) {
fputs(tok, stdout);
}
}
putchar('\n');
}
free(copy);
return 0;
}
I am new to C, and trying to implement whoami, as an exercise to myself. I have following code:
#define _POSIX_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h> // strtok
int str_to_int(const char *str)
{
int acc = 0;
int i;
for (i = 0; str[i] != '\0'; ++i) {
acc = (10 * acc) + (str[i] - 48); // 48 -> 0 in ascii
}
return acc;
}
int main()
{
FILE *passwd;
char *line = NULL;
size_t line_size;
passwd = fopen("/etc/passwd","r");
uid_t uid = getuid();
while (getline(&line, &line_size,passwd) != -1) {
char *name = strtok(line,":");
strtok(line,":"); // passwd
char *user_id = strtok(line,":");
if (str_to_int(user_id) == uid) {
printf("%s\n",name);
break;
}
}
fclose(passwd);
return 0;
}
Do I need to save line pointer inside of the while loop. Because I think strtok modifies it somehow, but I am not sure if I need to copy the line, or starting address of the line before I use it with strtok.
strtok is a horrid function. I don't know what documentation you read (if any?) but it both modifies the buffer it is passed and retains an internal pointer into the buffer; you should only pass the buffer the first time you use it on a given line, and pass NULL subsequently so it knows to pick up where it left off instead of starting at the beginning again (which won't actually work quite right because it stomped on the buffer...).
Better, find some other way to parse and stay far away from strtok.
It might be safer to use strtok_r. It is safer in a multi-threaded situation. That may not apply in this case, but it is sometimes better just to assume that some point any snippet you write might end up in a multi-threaded app. The following is the OP code modified to use strtok_r.
char *pos;
char *name = strtok_r(line,":",&pos);
strtok_r(NULL,":",&pos); // passwd
char *user_id = strtok_r(NULL,":",&pos);
And, yes, strtok (and strtok_r) do modify the given input buffer (first parameter). But it can be safe if used properly. Since strtok returns a pointer to a buffer inside the given string, you need to be careful how you use it. In your case, when it breaks out of the loop, name and user_id will point to a value inside the line buffer.
And you maybe should read the man pages for getline. The way you are using it, it returns an allocated buffer that your application is responsible for freeing. That might be what you are aiming for, but I mention it because I don't see a free call for it in the posted code.
I totally agree with geekosaur (and Mark). Paraphrasing his comment, you can modify the above code as following:
while (getline(&line, &line_size, passwd) != -1) {
char *name = strtok(line,":");
strtok(NULL,":"); // passwd
char *user_id = strtok(NULL,":");
if (str_to_int(user_id) == uid) {
printf("%s\n",name);
break;
}
}
You should pass NULL for the strtok invocations other than the first one.
I'm posting this as a vent for my questions (I will have a multitude). I decided it would be rather annoying to keep asking the same person one question at a time (said person is very busy), so I'll be posting questions as I come across them in my project. If you feel like helping, please do, and I would greatly appreciate it!
Note: this means I'll be updating this post frequently. Help is greatly, greatly appreciated as always.
EDIT so you guys want me to just keep posting different questions if I come across them? Of course I always do research before asking you guys, you talented group of men and women only get the most persistent of errors.
My first question:
I keep getting the error:
lvalue required as left operand of assignment
THE PURPOSE of this code is to copy the first n character up to ':'. For instance, if currentline is: "LABEL: .long 100" then GetLabelName would return "LABEL".
NOTE strncpy isn't working for this. It returns the remaining characters after ignoring the first n characters instead of just returning the first n characters...
Here's the code that's causing the error:
char *GetLabelName(char *currentline){
char *labelname[200];
while((((*labelname)++)=(*currentline)++)!=':');
return labelname;
}
Something is fishy about this code I guess, but I can't figure out what. Any ideas?
What I think you're trying to do is extract/copy all of the characters in a string up until a certain point (':' or NUL) and return that buffer. If that's the case, you're going to need to dynamically allocate memory for the new string (you can't return a local buffer allocated on the stack), and you should also take advantage of functions in <string.h> like strchr and memcpy.
Here's an alternative working example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *extract_string(char *str, char delim)
{
size_t len;
char *new_str;
char *delim_pos = strchr(str, delim);
/* new string is the length from the start of the old string to the
* delimiter, or if it doesn't exist, a copy of the whole string */
if (delim_pos == NULL)
return strdup(str);
len = delim_pos - str;
new_str = malloc(len + 1);
memcpy(new_str, str, len);
new_str[len] = '\0'; /* NUL terminate the new string */
return new_str;
}
int main(void)
{
char *extracted1 = extract_string("some:string", ':');
char *extracted2 = extract_string("no delimiter", ':');
puts(extracted1);
puts(extracted2);
/* free the dynamically allocated buffers */
free(extracted1);
free(extracted2);
return 0;
}
Output:
some
no delimiter
If you don't want to make a copy when the delimiter isn't found, you could alternatively return NULL.
Alternatively, if you don't mind mangling your initial string, you could use strtok to extract tokens.
The problem is (*labelname)++. You are incrementing the value that's pointed to by labelname and simultaneously assigning to it the value that's pointed to by currentline. If you want to increment the pointers, use *labelname++ and *currentline++