compare unsigned char array in C - c

This is the output of my program:
Username: paolo
Password: paolo
254835d73cc88095a30fc74133beabe9d8463b2954493227b205ea326c8a9c86
254835d73cc88095a30fc74133beabe9d8463b2954493227b205ea326c8a9c86
No user or password inside the database;
And this is my program:
int main(void){
int isok = -1;
char *user = NULL, *pass = NULL;
printf("Username: ");
if(scanf("%m[^\n]%*c", &user) == EOF){
perror("scanf user");
return EXIT_FAILURE;
}
printf("Password: ");
if(scanf("%m[^\n]%*c", &pass) == EOF){
perror("scanf");
free(user);
return EXIT_FAILURE;
}
isok = check_login(user, pass);
if(isok == 0){
/* some code here */
}
else{
/* some code here */
}
return EXIT_SUCCESS;
}
int check_login(char *u, char *p){
int retval = -1;
FILE *fp = NULL;
char *tmp, *tmp2, *line = NULL;
/* some code here */
while(fgets(line, 255, fp) != NULL){
tmp = strtok(line, " ");
if(tmp == NULL){
perror("strtok 1");
free(u);
free(p);
free(line);
free(fp);
return -1;
}
tmp2 = strtok(NULL, "\n");
if(tmp2 == NULL){
perror("strtok 2");
free(u);
free(p);
free(line);
free(fp);
return -1;
}
retval = hash_pwd(p, (unsigned char *)tmp2);
if((strcmp(tmp,u) == 0) && (retval == 0)){
free(line);
free(fp);
return 0;
}
else{
continue;
}
}
return -1;
}
int hash_pwd(char *to_hash, unsigned char *tocheck){
SHA256_CTX context;
unsigned char md[SHA256_DIGEST_LENGTH];
size_t length = strlen((const char*)to_hash);
int i;
SHA256_Init(&context);
SHA256_Update(&context, (unsigned char*)to_hash, length);
SHA256_Final(md, &context);
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
printf("%02x", md[i]);
}
printf("\n%s\n", tocheck);
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
if(md[i] == tocheck[i]) continue;
else return 1;
}
return 0;
}
Why my comparision inside the function hash-pwd doesn't work?What am i doing wrong?

The reason it is not working is that one is a pointer to an ascii string that contains a hex value; and the other is an array of binary value (which you are printing as hex).
....
// print out the digest - a binary array of SHA256_DIGEST_LENGTH
// bytes printed in hex
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
printf("%02x", md[i]);
}
// A string of SHA256_DIGEST_LENGTH *2 + 1 length - containing
// the value in hex spelled out in ascii.
printf("\n%s\n", tocheck);
So you need to convert either to the other. And then compare.

How do you know that the hash comparison is failing? It could just as well be the strcmp() call:
if((strcmp(tmp,u) == 0) && (retval == 0)){
For instance, are you sure tmp doesn't contain a newline that is missing in u?
Also, not sure if you're handling the hash loading properly, if you have a long string of hex characters in the file, that will need to be converted to binary before being
compared. The hash computed by SHA256 is binary, not hex string.
There are two (in my opinion) reasonable ways of fixing this:
Convert the hash read from the file to binary, before comparing
Convert the hash computed at runtime to text, before comparing
You can see that the two solutions are each other's complement, which seems natural to me. I would not encourage the solution you mentioned in a comment, involving temporary files.
Of the above, the second one is probably the easiest to implement, since it's easier to convert a bunch of bytes into hex than doing the reverse. It's the solution I would go with, something like:
static int hash_to_string(char *output, size_t output_max,
const unsigned char *hash, size_t hash_size)
{
size_t i;
if(output_max < 2 * hash_size + 1)
return 0;
for(i = 0; i < hash_size; ++i)
sprintf(output + 2 * i, "%02x", hash[i] & 0xff);
output[2 * i] = '\0';
return 1;
}
call the above with a pointer to a buffer large enough to hold the string version, then compare that against the one loaded from the file.
UPDATE: Or, you can use the existing API and just call SHA256_End() to get the hash in hex.
As a general observation, don't do this:
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
if(md[i] == tocheck[i]) continue;
else return 1;
}
return 0;
instead, do this:
return memcmp(md, tocheck, sizeof md) != 0;

Related

some parts of the text retrieved from txt file via fgets got lost in c

I am reading a file called "dictionary.txt" by fgets and print out, but like 10% of the head text from the "dictionary.txt" is lost when I run the program.
I suspect whether it is the size of the buffer is small, but changing MAX_INT to bigger numbers doesn't help either.
#include <stdio.h>
#include<string.h>
#define MAX_INT 50000
void main() {
FILE *fp;
char* inp = (char*)malloc(sizeof(char)*MAX_INT);
int i;
int isKorean = 0;
char* buffer[MAX_INT];
char* ptr = (char*)malloc(sizeof(char)*MAX_INT);
if (fp = fopen("C://Users//user//Desktop//dictionary.txt", "r")) {
while (fgets(buffer, sizeof(buffer), fp)) {
ptr = strtok(buffer, "/"); //a line is looking like this : Umberto/영어("English" written in Korean)
for (i = 0; i < strlen(ptr); i++) {
if ((ptr[i] & 0x80) == 0x80) isKorean = 1; //check whether it's korean
if (!isKorean) printf("%c", ptr[i]); //if it's not korean, then print one byte
else {
printf("%c%c", ptr[i], ptr[i + 1]); //if it's korean, then print two bytes
i++;
}
isKorean = 0;
printf("\n");
}
ptr = strtok(NULL, " ");
printf("tagger:%s\n", ptr); //print the POS tagger of the word(it's in dictionary)
}
fclose(fp);
}
}
The function fgets has this syncpsis:
char *
fgets(char * restrict str, int size, FILE * restrict stream);
So why make buffer as pointer array?
char buffer[MAX_INT] is what we need.
And the following statement:
if (fp = fopen("/Users/weiyang/code/txt", "r")) is not safe, it’s better to add parentheses after assignment.
Okay, I found the answer.
By adding below after the "ptr = strtok(NULL, " ");" just worked. I also had to do something with the tagger part because it is also written in Korean.
ptr = strtok(NULL, " ");
for (i = 0; i < strlen(ptr); i++) {
printf("%c%c", ptr[i], ptr[i + 1]); //if it's korean, then print two bytes
i++;
}

C code to read config file and parse directives

I'm trying to read a config file and parse the config directives. So far I have the following code, I need advice on how to improve this or change it. Is this efficient? Thanks!
struct config
{
char host;
char port;
}
void parse_line(char *buf) {
char *line;
if(strstr(buf, "host=") || strstr(buf, "host = ") || strstr(buf, "host= ") || strstr(buf, "host =")) {
line = strstr(buf, "=");
printf("Host: %s", &line[2]);
} else if(strstr(buf, "port=") || strstr(buf, "port = ") || strstr(buf, "port= ") || strstr(buf, "port =")) {
line = strstr(buf, "=");
printf("Port: %s", &line[2]);
}
}
int main(int argc, char *argv[])
{
char *file_name;
FILE *file;
file_name = argv[1];
file = fopen(file_name, "r");
// check if file is NULL, etc..
char buffer[BUFSIZ];
char *line;
int i;
while(fgets(buffer, sizeof(buffer), file) != NULL) {
for(i = 0; i < strlen(buffer); i++) { // iterate through the chars in a line
if(buffer[i] == '#') { // if char is a #, stop processing chars on this line
break;
} else if(buffer[i] == ' ') { // if char is whitespace, continue until something is found
continue;
} else {
parse_line(buffer); // if char is not a # and not whitespace, it is a config directive, parse it
break;
}
}
}
fclose(file);
return 0;
}
I am looking for a way to ignore # if it is a first character on a line, and also lines that are white spaces. I think my code does that, but is that efficient?
EDIT:
Thanks everyone for all the suggestions, I have managed to do this simple code to trim the white spaces, so that I wouldn't need all the strstr() calls.
void trim(char *src)
{
int i, len;
len = strlen(src);
for(i = 0; i < len; i++) {
if(src[i] == ' ') {
continue;
}
if(src[i] == '\n' || src[i] == '#') {
break;
}
printf("%c", src[i]); // prints: host=1.2.3.4
}
}
int main(void)
{
char *str = "host = 1.2.3.4 # this is a comment\n";
trim(str);
return EXIT_SUCCESS;
}
It prints correctly: host=1.2.3.4 but now I need this in a variable to be further parsed. I think I will try to use strcpy.
EDIT 2:
I do not think that strcpy is the right choice. Those chars are printed out in a loop, so every time I use strcpy, the previous char is overwritten. I have tried this, but it does not work because only the host= part is placed into arr. The IP part is not placed into arr.. how can this be fixed..
char arr[sizeof(src)];
for(i = 0; i < len; i++) {
if(src[i] == ' ') {
continue;
}
if(src[i] == '\n' || src[i] == '#') {
break;
}
printf("%c", src[i]); // prints: host=1.2.3.4
arr[i] = src[i];
}
int j;
for(j = 0; j < sizeof(arr); j++) {
printf("%c", arr[j]); //prints: host=
}
EDIT 3:
I found the correct way of placing chars into arr:
int i, count = 0;
for(i = 0; i < len; i++) {
if(src[i] == ' ') {
continue;
}
if(src[i] == '\n' || src[i] == '#') {
break;
}
arr[count] = src[i];
count++;
}
Your implementation is pretty fragile. Parsers really ought to verify syntax and return errors when they see something unexpected. For example, yours should detect missing fields and multiply defined ones.
Fortunately this parsing problem is simple enough for sscanf to handle everything:
skip blank lines,
skip comments
ignore any amount of whitespace
extract the key/value pairs
Here's code:
#include <stdio.h>
#define CONFIG_SIZE (256)
#define HOST_SET (1)
#define PORT_SET (2)
typedef struct config {
unsigned set;
char host[CONFIG_SIZE];
unsigned long port;
} CONFIG;
// Parse the buffer for config info. Return an error code or 0 for no error.
int parse_config(char *buf, CONFIG *config) {
char dummy[CONFIG_SIZE];
if (sscanf(buf, " %s", dummy) == EOF) return 0; // blank line
if (sscanf(buf, " %[#]", dummy) == 1) return 0; // comment
if (sscanf(buf, " host = %s", config->host) == 1) {
if (config->set & HOST_SET) return HOST_SET; // error; host already set
config->set |= HOST_SET;
return 0;
}
if (sscanf(buf, " port = %lu", &config->port) == 1) {
if (config->set & PORT_SET) return PORT_SET; // error; port already set
config->set |= PORT_SET;
return 0;
}
return 3; // syntax error
}
void init_config(CONFIG *config) {
config->set = 0u;
}
void print_config(CONFIG *config) {
printf("[host=%s,port=", config->set & HOST_SET ? config->host : "<unset>");
if (config->set & PORT_SET) printf("%lu]", config->port); else printf("<unset>]");
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s CONFIG_FILE\n", argv[0]);
return 1;
}
FILE *f = fopen(argv[1], "r");
char buf[CONFIG_SIZE];
CONFIG config[1];
init_config(config);
int line_number = 0;
while (fgets(buf, sizeof buf, f)) {
++line_number;
int err = parse_config(buf, config);
if (err) fprintf(stderr, "error line %d: %d\n", line_number, err);
}
print_config(config);
return 0;
}
With this input:
# This is a comment
This isn't
# Non-leading comment
host = 123.456.789.10
###
port =42
port= 1
host=fruit.foo.bar
the output is
error line 3: 3
error line 10: 2
error line 11: 1
[host=fruit.foo.bar,port=1]
Note that when the parser discovers a field has already been set, it still uses the latest value in the config. It's easy enough to keep the original instead. I'll let you have that fun.
I think parse_line is a little bit rigid for my taste, I would use strtok
instead. Then you don't have to worry too much about spaces, like you do if you
have a space before the = sign.
Your struct is also wrong, host and port would only hold a character.
Besides port should be an integer. And you need a semicolon ; after the
struct definition.
struct config
{
char host[100];
int port;
};
int parse_line(struct config *config, char *buf)
{
if(config == NULL || buf == NULL)
return 0;
char varname[100];
char value[100];
const char* sep = "=\n"; // get also rid of newlines
char *token;
token = strtok(buf, sep);
strncpy(varname, token, sizeof varname);
varname[sizeof(varname) - 1] = 0; // making sure that varname is C-String
trim(varname);
token = strtok(NULL, sep);
if(token == NULL)
{
// line not in format var=val
return 0;
}
strncpy(value, token, sizeof value);
value[sizeof(varname) - 1] = 0
trim(value);
if(strcmp(varname, "port") == 0)
{
config->port = atoi(value);
return 1;
}
if(strcmp(varname, "host") == 0)
{
strncpy(config->host, value, siezof config->host);
config->host[(sizeof config->host) - 1] = 0;
return 1;
}
// var=val not recognized
return 0;
}
Note that I used a function called trim. This function is not part of the
standard library. Below I posted a possible implementation of such a function.
I like using trim because it gets rid of white spaces. Now you can do this in
main:
struct config config;
// initializing
config.port = 0;
config.host[0] = 0;
int linecnt = 0;
while(fgets(buffer, sizeof(buffer), file) != NULL) {
linecnt++;
trim(buffer);
if(buffer[0] == '#')
continue;
if(!parse_line(&config, buffer))
{
fprintf(stderr, "Error on line %d, ignoring.\n", linecnt);
continue;
}
}
A possible implementation of trim
void rtrim(char *src)
{
size_t i, len;
volatile int isblank = 1;
if(src == NULL) return;
len = strlen(src);
if(len == 0) return;
for(i = len - 1; i > 0; i--)
{
isblank = isspace(src[i]);
if(isblank)
src[i] = 0;
else
break;
}
if(isspace(src[i]))
src[i] = 0;
}
void ltrim(char *src)
{
size_t i, len;
if(src == NULL) return;
i = 0;
len = strlen(src);
if(len == 0) return;
while(src[i] && isspace(src[i]))
i++;
memmove(src, src + i, len - i + 1);
return;
}
void trim(char *src)
{
rtrim(src);
ltrim(src);
}
There are a few ways that you can improve performance:
Calling strstr() in this scenario is inefficient, because the presence of the "host" part of buf can be checked once instead of multiple times every time strstr() is called. Instead, make an if statement that checks if buf begins with "host", then check if buf contains the other elements. The same thing applies to the portion of code checking for the presence of "port".
In the loop in main, instead of doing this:
for(i = 0; i < strlen(buffer); i++) { // iterate through the chars in a line
if(buffer[i] == '#') { // if char is a #, stop processing chars on this line
break;
} else if(buffer[i] == ' ') { // if char is whitespace, continue until something is found
continue;
} else {
parse_line(buffer); // if char is not a # and not whitespace, it is a config directive, parse it
break;
}
do this:
for(i = 0; i < strlen(buffer); i++) { // iterate through the chars in a line
char temp = buffer[i];
if(temp == '#') { // if char is a #, stop processing chars on this line
break;
} else if (temp != ' ') {
parse_line(buffer); // if char is not a # and not whitespace, it is a config directive, parse it
break;
}
Checking to see if something is not equal to another is likely to be just as fast as checking if they are equal (at least on Intel, the je (jump equal) and jne (jump not equal) instructions exhibit the same latency of 1 cycle each), so the statement with the continue in it is not necessary. The temp variable is so that buffer[i] does not need to be calculated in the second if again in case the first if is false. Also, do what user3121023 stated below (same reason for performance as creating the temp variable).
You can use operating-system-specific functions (such as thos from the library WINAPI/WIN32/WIN64 (synonyms) on windows) instead of C standard library functions. Microsoft has very good documentation about their functions in the MSDN (Microsoft Developer Network) web site.
Use uint_fast8_t (defined in stdint.h, this typedef is set to the fastest integer type greater than or equal to the size in bits specified in the typedef) when performing operations on the host and port (but use chars when storing the variables on the disk, in order to make read i/o operations faster).
This isn't related to performance , but use return EXIT_SUCCESS; in main instead of return 0;, since using EXIT_SUCCESS is more readable and exhibits the same performance.
Honestly, I can't help but wonder if rolling your own parser is so great.
Why not use an existing JSON or YAML parser and test for keys in the parsed data?
This will be easily extendible by allowing for new keys to be added with very little effort and the common format of the configuration file makes it very easy for developers to edit.
If you are going to roll out your own parser, than some of the previously mentioned advice makes a lot of sense.
The biggest ones are: don't seek the whole buffer, read the single line that's in front of you and report any errors. Also, advance as you go.
Your parser should work correctly if someone would dump a GigaByte of garbage into the configuration file, so make no assumptions about the data.

Why is reading from file function crashing?

Trying to read multiple line from file to store them in a structure made up of the string elements, however when I run the program it simply crashes and I haven't the faintest idea why.
function in question:
Hashtbl* loadfromfile(Hashtbl* hashtbl, char *path){
int i = 0;
char line[100];
char* string[40];
FILE *f = fopen(path, "r");
if(f == NULL){
printf("FILE NO FOUND!");
}else{
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
fclose(f);
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
for(i = 1; i<(SIZE*2); i++){
strcpy(hashtbl[i].value, string[i]);
i++;
}
return hashtbl;
}
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"
int main() {
Hashtbl* numbers;
numbers = init_hashtbl(); //init_hashtable initialises numbers
loadfromfile(numbers, "test.txt");
for(int i = 0; i<SIZE; i++) {
printf("%s1", numbers[i].subscript);
printf("%s2\n", numbers[i].value);
}
}
Hashtable structure:
typedef struct Hashtbls{
char *subscript;
char *value;
} Hashtbl;
init_hasthable function:
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = "ZERO";
hashtbl[i].value = "ZERO";
}
return hashtbl;
}
You have quite a few problems here:
if(f == NULL){
printf("FILE NO FOUND!");
}
If the file cannot be opened, then you cannot continue. Also the message might
be printed way later, use printf("FILE NOT FOUND!\n"); instead.
char* string[40];
...
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
string is an array of uninitialized pointers, you cannot write anything
there. You should do
while(fgets(line, sizeof line, f))
{
string[i] = malloc(strlen(line) + 1);
if(string[i] == NULL)
{
// error handling is needed
}
strcpy(string[i], line);
i++;
if(i == sizeof string / sizeof *string)
break;
}
// or if your system has strdup
while(fgets(line, sizeof line, f))
{
string[i] = strdup(line);
if(string[i] == NULL)
{
// error handling is needed
}
i++;
if(i == sizeof string / sizeof *string)
break;
}
Also you are not checking whether you read more than 40 lines. I did that with
the the last if. sizeof array / sizeof *array returns the number of
elements that an array can hold. Note that this only works for arrays, not
pointers, since in general sizeof array != sizeof pointer. Also don't forget
to free the allocated memory afterwards.
strcpy(hashtbl[i].subscript, string[i]);
...
strcpy(hashtbl[i].value, string[i]);
Are the subscript and value parameters here initialized in some way? Check
your init_hashtbl().
EDIT
Now that you posted init_hashtbl:
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
You are initializing subscript and value with string literals, they
are pointing to read-only memory location, strcpy is going to fail. You have
to either allocate memory with malloc or change your structure with arrays.
Option 1
Keep the structure, change init_hashtbl
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].subscript, "ZERO");
hashtbl[i].value = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
You should always check the return value of malloc/calloc. Also the
problem here is that if you want to copy a string that is longer than
SOME_MAXIMAL_LENGTH, you are going to have a buffer overflow. So you should
use realloc in the reading routine:
for(i = 0; i<(SIZE*2); i++){
char *tmp = realloc(hashtbl[i].subscript, strlen(string[i]) + 1);
if(tmp == NULL)
{
// error handling
}
hashtbl[i].subscript = tmp;
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
If you don't want to deal with realloc here, you have to make sure, that no
string[i] is longer than SOME_MAXIMAL_LENGTH.
Option 2
Change you structure and init:
typedef struct Hashtbls{
char subscript[SOME_MAXIMAL_LENGTH];
char value[SOME_MAXIMAL_LENGTH];
} Hashtbl;
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
strcpy(hashtbl[i].subscript, "ZERO");
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
Then in loadfromfile you don't have to deal with the realloc as shown
above, you can keep your code. However, you have to check that no string[i]
is longer than SOME_MAXIMAL_LENGTH - 1, otherwise buffer overflow.
One last thing, fgets reads a whole line, assuming that the length of the
line is lesser than sizeof line, the newline character will be added to the
line. You most likely don't want to have that. One way of getting rid of the
newline is:
fgets(line, sizeof line, f);
int len = strlen(line);
if(line[len - 1] == '\n')
line[len - 1] = 0;

Comparing char* in C using strcasecmp

I'm reading bytes from a socket and copying it into a char array.
char usrInputStr[256];
if ((rbytes = read(STDIN_FILENO, usrInputStr, 256)) < 0) {
perror("Read error: ");
exit(-1);
}
char finalStr[rbytes + 1];
memcpy(finalStr, usrInputStr, rbytes);
Now I allot an array on the heap and split the string into words and put each word in an array of char arrays. This is the code that does that.
char** currentTokens = (char**)malloc(sizeof(char*) * 256);
for(int i = 0; i < 256; i++) {
currentTokens[i] = (char*)malloc(sizeof(char) * 256);
}
int sz = splitStrToArray(finalStr, currentTokens);
The definition of the splitStrToArray function is here,this works fine.
int splitStrToArray(char* str, char** arr) {
int count = 0;
char* buffer;
int len = strlen(str);
for (int i = 0; i < len ; ++i) {
if(isspace(str[i])) {
count++;
}
}
int index = 0;
buffer = strtok(str, " ");
while(buffer != NULL) {
memcpy(arr[index], buffer, strlen(buffer));
index++;
buffer = strtok(NULL, " ");
}
return count;
}
However when I compare this with user input it doest return zero and thus the two string don't match.
if(strncasecmp(currentTokens[0], "quit") == 0) {
printf("quit" );
breakTrigger = 1;
} else if(strcasecmp(currentTokens[0], "q") == 0) {
printf("q");
breakTrigger = 1;
} else {
callback(currentTokens, sz, port);
}
I've checked currentTokens[0] and the word is correct.
When the I try to take the return value of strcasecmp in an int and print it I get Segmentation Fault.
I'm new to C, any help appreciated.
None of your strings are null-terminated so you have undefined behaviour throughout. Using memcpy to copy strings is almost never what you want.
You should consider using strdup, if available. Otherwise malloc and then strcpy.
In the particular case of finalStr, I see no good reason to perform the copy at all. Just read directly into it (and don't forget to null-terminate.) Alternatively, use the standard C library instead of the underlying posix layer.

Append a character to function input?

I need the send and integer to a function and then append that to the end of a constant character.
int main (void)
{
append(1);
}
int append(int input)
{
const char P = 'P';
//This where I want to append 1 to P to create "P1"'
}
No matter what you do, you need to convert the number to a string, otherwise you can't create a string containing both numbers.
You can actually combine both the concatenation and the int-to-string conversion in one function call: sprintf:
char output[16];
sprintf(output, "P%d", input);
I'm not an expert on C, but I don't believe constants should be changed once they are defined.
Not sure if you can add something to a const chat (since its a const).
But why not:
char p[3];
sprintf(p, "P%d",input);
You cannot assign more than one character value to a char. For doing that you would have to take a string. Maybe like this.
int append(int input)
{
const char P = 'P';
//This where I want to append 1 to P to create "P1"
char app[2] ; //extend that for your no. of digits
app[0] = P '
app[1] = (char) input ;
}
This is for one digit. You can allocate dynamic memory for big integers and do the same in a loop.
What about using strncat?
See a working example on codepad: http://codepad.org/xdwhH0ss
I would convert the number to a string (assuming you have access to a function called itoa in this example and concatenate it to the character. If you don't have access to itoa you could sprintf instead.
itoa method:
#include <stdio.h>
#include <stdlib.h>
char *foo(const char ch, const int i)
{
char *num, *ret;
int c = i;
if(c <= 0) c++;
if(c == 0) c++;
while(c != 0)
{
c++;
c /= 10;
}
c += 1;
if(!(num = malloc(c)))
{
fputs("Memory allocation failed.", stderr);
exit(1);
}
if(!(ret = malloc(c + 1)))
{
fputs("Memory allocation failed.", stderr);
free(num);
exit(1);
}
itoa(i, num, 10);
ret[0] = ch;
ret[1] = 0x00;
strcat(ret, num);
free(num);
return ret;
}
int main(void)
{
char *result;
if(!(result = foo('C', 20))) exit(1);
puts(result);
free(result);
return 0;
}
sprintf method:
#include <stdio.h>
#include <stdlib.h>
char *foo(const char ch, const int i)
{
char *num, *ret;
int c = i;
if(c <= 0) c++;
if(c == 0) c++;
while(c != 0)
{
c++;
c /= 10;
}
c += 1;
if(!(num = malloc(c)))
{
fputs("Memory allocation failed.", stderr);
exit(1);
}
if(!(ret = malloc(c + 1)))
{
fputs("Memory allocation failed.", stderr);
free(num);
exit(1);
}
sprintf(num, "%d", i);
ret[0] = ch;
ret[1] = 0x00;
strcat(ret, num);
free(num);
return ret;
}
int main(void)
{
char *result;
if(!(result = foo('C', 20))) exit(1);
puts(result);
free(result);
return 0;
}
I compiled and tested both of these and they seem to work quite nicely. Good luck.

Resources