I have used sscanf to scan in a string and add it to a structure. The only problem is that I cannot print out the string because there is no null terminator added by default. I tried to add a null in there with the strcat() function but came to the realization this cannot work. Thanks for any help.
struct a
{
int *ref;
char string[50];
}rec;
void task()
{
char *p_test;
char test[50] = "9999:STRING OF TEXT";
p_test = test;
sscanf(p_test, "%d:%[^\n]", &rec.ref, rec.string);
printf("String is:%s", &rec.string);
}
There are multiple problems with your code.
test[50] = "9999:STRING OF TEXT";
This is wrong for two reasons.
A) test is an array of char, not an array of char*. So, when you assign a string (a char*) to an element, the address is converted to a char.
B) Element 50 does not exist in your array, and writing to it invokes undefined behavior. You have an array of 50 elements with indices 0...49.
To assign an initial value to your array, all you need do is:
char test[50] = "9999:STRING OF TEXT";
And since test does not need to be modified...
const char *test = "9999:STRING OF TEXT";
If you want to zero an array, the simplest method is:
char test[50] = {0};
Of course, you don't need to if you assign the string properly to begin with, and this is not your problem.
Your string member of the a struct is a char, not a char* (a string), and using the %s format specifier when printing it invokes undefined behavior.
main is defined to return int, not void.
sscanf expects pointers to data to fill in. rec.ref is an int, you need to pass its address, i.e., &rec.ref.
You need to allocate storage for rec.string.
Here is a working example:
#include <stdio.h>
#define STRING_LEN 50
struct a
{
int ref;
char string[STRING_LEN];
} rec;
int main()
{
char test[STRING_LEN] = "9999:STRING OF TEXT";
// note that, in the real world, this may
// be a buffer overflow waiting to happen
sscanf(test, "%d:%[^\n]", &rec.ref, rec.string);
printf("String is:%s, rec is:%d", rec.string, rec.ref);
return 0;
}
You have a number of problems; a lack of null-terminator actually isn't one of them.
One problem is a syntax error; this:
char test[50]
test[50] = "9999:STRING OF TEXT";
is not valid syntax. You need:
char test[50] = "9999:STRING OF TEXT";
Another problem is that rec doesn't have a string (a char * or char[]), it just has a single character (a char). A simple approach, to get you started, is:
struct a
{
int ref;
char string[50];
} rec;
A third problem is that sscanf's arguments all have to be pointers. C is a pass-by-value language; if you just pass in an integer, that doesn't give sscanf any way to modify that integer:
sscanf(test, "%d:%[\n]", &rec.ref, rec.string); // (once rec.string is a pointer)
A fourth problem is that the format-specifier %[\n] does not mean what you seem to want it to mean. (Maybe you actually wanted %[^\n]?)
Other, smaller issues include your return-type for main (it should be int, not void).
The common thread with most of these issues is that your compiler would have eagerly helped you identify them, had you simply turned on compiler warnings!
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have this code:
char** SplitToWords(char* str);
int main()
{
char** wordarr;
char str[] = "This is a sentence";
wordarr = SplitToWords(str);
return 0;
}
After the main comes the function implementation.
I am not sure the following does what I want it to do (i.e. receive an array of strings from a function):
wordarr = SplitToWords(str);
I somehow managed to convince the compiler that it's ok, but I assume it just does something else.
If it does, how do I find out the length of the array (the number of strings in it).
Thanks
I'll try to quickly visit all aspects you might not yet fully understand:
A string in C is described as a contiguous sequence of chars, ending with a char of value 0 (as a literal: '\0'). It is not a first class object, therefore hasn't its own type. So what you use to hold a string is an array of char. Therefore, taking your question by the word, "receive an array of strings from a function" is not possible.
An array is a contiguous sequence of objects of the same type. In C, the identifier of an array doesn't have a value itself; when it's evaluated, it decays as a pointer to the array's first element instead. This is especially important when passing arrays to functions or returning them from functions -- you can't actually pass the array, you always pass a pointer
e.g. you could write:
char x[] = "foo"; // initialize a char array from a string literal
char *xp = x; // here, x evaluates as a pointer to the first element of the array
You already use pointer types for your function's argument and return value, I just think it's quite important to understand what happens entirely.
You write char** SplitToWords(char* str); and ask whether this returns an "array of strings" -- well, sort of, as you should understand after reading 1. and 2. -- What it does is returning a pointer to char *. This pointer could be a pointer to the first element of an array. So in this case, it would return a pointer to an array of char * pointers. Each of these pointers could itself be a pointer to an array of chars, therefore point to a string. But what's very important is to understand you never return an array, you always return a pointer to it. It's so important because:
You might get the idea to do something like this:
char** SplitToWords(char* str)
{
char *words[16];
// code to fill `words` with pointers to the actual words
return words; // WRONG!
}
Here, because you're not returning the array words but a pointer to it (see point 2), you return a pointer to an object that no longer exists. words is in the scope of your function and has automatic storage duration, that means it only lives as long as the execution is inside of the function. One solution would be to declare words with the static storage class specifier. This way, it lives for the entire execution time of the program. But be aware that this also means there's only a single instance ever, it's always the same object. This will be a major headache for threaded programs, for example. The other way around is to dynamically allocate words using malloc(). But then, the caller of the function must free() it later.
As for your second question, how to let the caller know the number of words -- it's in the comments already, but just for completeness, a typical approach to solve this is to append another entry that is a NULL pointer. So the caller can iterate over the pointers until it finds NULL.
Regarding your comment, of course you can create the array outside the function and pass a pointer to the function, so the function only fills it. This is a common idiom in C (e.g. think about fgets(), which takes a pointer to the char array that's filled with a string by the function).
Functions working this way will need an additional size_t parameter, so they know the size of the array they should fill through the pointer, otherwise you'd have the risk of buffer overflows (this is why gets() was finally removed from the C standard). If you decide that the caller provides the storage, your function should have this prototype:
// returns the number of words found, up to `nwords`
size_t SplitToTwords(char **words, size_t nwords, char *str);
It should be called e.g. like this:
char *words[16];
size_t nwords = SplitToWords(words, 16, "the quick brown fox"); // returns 4
Remember that the strings holding the words themselves need storage as well. You can either manipulate the bytes in str to insert a '\0' after each word, overwriting the first whitespace character (this is what strtok() does) or you can copy the words to new strings, but then you would have to malloc() each of them again and the caller has to free() them later.
Yes, you could solve it by using a function with return value char **. However, there's no way to find out how many words there are afterwards.
You can solve this by allocating one more element for the return pointer and set it to NULL. Then you can get the number of words with this code:
wordarr = SplitToWords(str);
char **ptr=wordarr;
int noWords=0;
while(!*(ptr+noWords))
noWords++;
But if you want to return multiple data in C, you either need to define a return struct or using return arguments. In this case, it could look like this for the first option:
typedef struct wordList {
char **wordarr;
int noWords;
}
wordList SplitToWords(char* str);
And the second:
char** SplitToWords(char* str, int *noWords);
or
void SplitToWords(char* str, char*** wordarr, int *noWords);
Note that there's three *. That's because we want it to be a pointer to char **
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSTRINGS 5000
int main(int argc, char *argv[]) {
char *stringTable[MAXSTRINGS];
char sentence[] = "This is a sentence";
char *token = NULL;
int i = 0;
while ((token = strtok(token == NULL ? sentence : NULL, " ")) != NULL)
{
printf("%s\n\r", token);
stringTable[i] = (char *)malloc(strlen(token) + 1); //have no "plain" C compiler - VS C++ used so cast needed :)
strcpy(stringTable[i++], token);
}
stringTable[i] = NULL; // if you need to iterate through later
printf("%d tokens found\n\r", i);
for (int y = 0; y < i; y++)
free(stringTable[y]);
}
I am writing a simple function in C that should build a char array from string "abc" – so it should build {'a','b','c'} – and return a pointer to that array. Here is my code for this function:
char * makeArr()
{
static char arr[3];
sprintf(arr, "%s\n", "abc");
return arr;
}
Problems occur when I call this method in main:
int main(int argc, char *argv[])
{
char *arr[3];
arr = makeArr();
return 0;
}
The compiler is complaining about casting / conflicting types. I've been playing with pointers, casting and dereferencing for quite a while now, but can't seem to get it to work. Please let me know where my logic is wrong.
Hmm ... there are several errors in this code. Let's start with the most obvious your compiler complains about:
char *arr[3];
This line declares arr to be an array of three pointers to char. What you return from your function is a single pointer to a char -> doesn't match.
Next:
static char arr[3];
sprintf(arr, "%s\n", "abc")
Here you reserve 3 chars. the sprintf() will write 5 chars. %s is replaced by the 3 characters in your string literal "abc". You add a newline character and then a 0 is added as the marker for the end of the "string". Makes 5. This btw is undefined behavior. You write past the end of your array. Code like this can be compiled, but there's no guarantee at all about what will happen at runtime.
Doing a cut here. You should read about arrays and pointers in C. If the text you're reading claims they are the same ... stop right there and find a better text. They aren't.
I'll try to explain this here briefly, so it's suitable for the Q&A style.
An array in C indeed is a contiguous space of several values. char arr[3] means a variable that holds 3 chars.
On the other hand, a char * is just a pointer pointing to a char -- this could be the first element of an array.
In C, you can't pass arrays as function parameters, and you can't return arrays from a function. Trying to do so leads to an implicit conversion: What is actually passed is a pointer to the first element of that array.
I think the last bit of information missing is what a string literal in C is: it's an array (anonymous, e.g., it doesn't have a name) containing all the characters in the double quotes plus a 0 appended. The 0 marks the end of a "string" in C.
In an expression, a string literal evaluates to a pointer to the first element.
So, something like this:
char *foo = "bar";
will lead to foo pointing to the b of the array. It's like writing
static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);
Among other things, you confused:
char arr[3]; // array of 3 chars.
and,
char *arr[3]; // array of 3 pointers to char.
In main(), you should only write char *arr;
Firstly, char arr[3]; is too snall to store "abc\n". It must have at least 5 elements including terminating null-character.
Then, char *arr[3]; is a 3-element array of char*.
You should assign makeArr()'s return value (it has char* type) to arr[0] or another element, or you should change the type of arr in main function to char*, which is the same type as makeArr()'s return value.
Moreover, this makeArr() doesn't make any array and returns (a pointer to) the existing array. Yoy should use malloc() to "make an array".
UPDATE:
Assigning a value of char* to the array char arr[10]; seems invalid in C.
You should use strcpy() or strncpy() (safer than strcpy()) to copy the string stored in the array between arrays.
Pass the array as an argument and modify it in the called function, would be easier. If you're statically creating the array and there's no need to allocate memory, don't, just pass around your pointers to the functions to be modified by reference
void makeArr(char arr[]){
sprintf(arr, "%s\n", "abc");
}
Simply pass the existing declared array to the makeArr function...
int main(int argc, char *argv[]) {
char arr[10];
makeArr(arr);
return 0;
}
You couldn't assign the result of makeArr to arr. I guess that's your casting error. Oversimplifying, arr points to the place on the stack where the array of 10 characters is allocated. So, I'd pass in arr to makeArr as a char*. So, you'd end up with something like this:
#include <stdio.h>
char * makeArr(char *arr)
{
sprintf(arr, "%s\n", "abc");
return arr;
}
int main(int argc, char *argv[])
{
char arr[10];
makeArr(arr);
printf("%s\n", arr);
return 0;
}
Below is my code:
#include <stdio.h>
#include <stdlib.h>
typedef int index_key;
typedef char text_t;
text_t *create_text()
{
//text_t text[SIZ];
text_t *c;
text_t text[]="fl";
c= text;
return c;
}
int main()
{
text_t * create();
return 0;
}
I get an error - expected expression before ‘]’ token. Why is this error occuring? Isn't text[] a global declaration and I can access it anywhere? What is wrong in this program and how should I correct it.
You cannot have an array definition like
text_t text[];
Either specify the size,
#define SIZ 256 //arbitary value
text_t text[SIZ];
or use initializer.
text_t text[] = {`A`, `B`, `C`};
EDIT:
As per the latest addition, please be informed that "sldk" (as you've iused) and {'s', 'd', 'l', 'k'} (as i've suggested) are not the same. The former is a string literal while the later being initalizer list of chars. You can use the second in your case, not the first one.
EDIT 2
That said, your create_text() function is wrong. Effectively, you're returning the address of a local variable text. Incorrect. Will invoke UB.
I see the following problems:
text_t text[];
is a declaration, not a definition. You have to add a line that defines text, such as:
text_t text[100];
The line
text[]="sldk";
is wrong on two accounts.
You cannot assign to an array using the = operator.
You cannot use text[] to access the array.
Here's a fixed version of your program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int index_key;
typedef char text_t;
// This is a forward declaration of the array.
text_t text[];
text_t *create()
{
text_t *c;
// One way to get some string into a char array.
strcpy(text,"sldk");
c = text;
return c;
}
// This is the definition of the array.
text_t text[100];
int main()
{
text_t * create();
return 0;
}
Update
Regarding your updated create_text function...
It should work since string literals are stored in read-only memory of the program. It will lead to problems as soon as you try to change anything in it. It's better to use a safer approach, such as:
text_t *create_text()
{
text_t *c = malloc(20);
strcpy(c, "fl");
return c;
}
The C language does not have a built in string data type unlike C++, Java or C#.
The strings are represented as arrays of characters in C. So any array in C should have some size.
int numbers[10];
char string[50];
The C function which operate on these types of strings ( like strlen which calculates the length of the strings expects a 'null' or '\0' character at the end of the array.
Initializing a character array with string literal like "test" will automatically insert a null character at the end.
char str[10] = "test";
characters stored {'t','e','s','t','\0'}
If you are initializing it with comma separated characters, you need to explicitly specify this character.
char str[10] = {'t','e','s','t', '\0'}; //explicit null character
So, generally the array size is one more than the maximum size of the string you want to store. So it is quite common to see declaration like the following.
char name[MAXLEN+1];
If you are using C++, you can use a build-in data type called string.
string str;
Hope this helps
I'm new to C and am having trouble declaring a character array for a class project.
Here's roughly what I'm doing:
char test[]="Test\0";
char *Pointer;
Pointer=test;
I then have a function printString(char* chars) that takes Pointer as an argument. When I try to compile, I'm told that neither test or Pointer are declared. I'm not sure why, so can someone point me in the right direction.
This is the whole code:
main()
{
char *test2="Test\0";
printString(test2);
}
printString(char* charArray)
{
int charPos=0;
int endOfString=1;
char al;
char ah;
int ax;
while(endOfString==1)
{
al=charArray[charPos];
ah=0xE;
ax=ah*256+al;
interrupt(0x10,ax,0,0,0);
if(al=='\0')
{
return 0;
}
charPos++;
}
}
First of all, having the NULL character is not necessary there.
Here is why:
When an array of characters is declared and it is initialize, like in your example:
char test[] = "Test";
The compiler will put the characters from "Test" in the test array, then add a null character so that test can be used as a string like so:
+---+---+---+---+----+
test| T | e | s | t | \0 |
+---+---+---+---+----+
In regards to your question, see if this helps:
void print_string( char *p ) {
while ( *p != '\0' ) {
printf( "%c", *p );
p++;
}
}
Remember a C-style string is a sequence of characters and it's always terminated with NULL character.
The function "print_string", for example, expects a pointer to a char as an argument ( you can past the char array you created, and it will work since arrays are treated as pointers. )
The function will print each character until the NULL character is encountered.
IMPORTANT:
char test[] = "Test";
char *test_2 = "Test";
In the array version, the characters stored in test can be modified, like elements of any array.
In the pointer version, test points to a string literal, and string literals should NOT be modified.
I believe the problem might be because of that, you are trying to modified a string literal. Doing so causes undefined behavior.
Either use an array or allocate memory and make char pointer point to it.
For use your function: printString(char* chars).
declare just:
char *my_string = "Test";
printString(my_string);
The problem is possibly because you don't declare the function before you use it. In C you really have to declare everything before it's used. In this case do e.g.
void printString(char* charArray);
int main(void)
{
...
}
void printString(char* charArray)
{
...
}
so i have a struct call Process_Info
struct Process_Info {
char name[128];
int pid;
int parent_pid;
int priority;
int status;
};
and an array of Process_Info call info. I set pid in info to an integer, it works but when I try to set name in info to "{kernel}" like this
info[i].name="{kernel}";
and it give me incompatible type in assignment error. I search online it seem i can do this, like in http://www.cs.bu.edu/teaching/cpp/string/array-vs-ptr/, they did char label[] = "Single"; So what am i doing wrong?
The short answer: A C compiler will bake constant strings into the binary, so you need to use strncpy (or strcpy if you aren't worried about security) to copy "{kernel}" into info[i].name.
The longer answer: Whenever you write
char label[] = "Single";
the C compiler will bake the string "Single" into the binary it produces, and make label into a pointer to that string. In C language terms, "Single" is of type const char * and thus cannot be changed in any way. However, you cannot assign a const char * to a char *, since a char * can be modified.
In other words, you cannot write
char label[] = "Single";
label[0] = "T";
because the compiler won't allow the second line. However, you can change info[i].name by writing something like
info[i].name[0] = '[';
because info[i].name if of type char *. To solve this problem, you should use strncpy (I referenced a manual page above) to copy the string "{Kernel}" into info[i].name as
strncpy(info[i].name, "{Kernel}", 256);
info[i].name[255] = '\0';
which will ensure that you don't overflow the buffer.
I think you may be mistaken. The way you would assign this would be one char at a time like so...
name[] = {'a','b','c','d'};