سؤال

أنا أعمل في ج و علي لسلسلة عدد قليل من الأشياء.

الآن لدي هذا:

message = strcat("TEXT ", var);

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));

الآن إذا كان لديك خبرة في ج أنا متأكد من أنك تدرك أن هذا يعطيك تجزئة خطأ عند محاولة تشغيله.فكيف العمل في ذلك ؟

هل كانت مفيدة؟

المحلول

في ج "سلاسل" عادي فقط char المصفوفات.ولذلك لا يمكنك مباشرة لسلسلة أخرى لهم "سلاسل".

يمكنك استخدام strcat الدالة التي ترفق سلسلة أشار إلى src إلى نهاية السلسلة إلى طريق dest:

char *strcat(char *dest, const char *src);

هنا على سبيل المثال من cplusplus.com:

char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");

أول معلمة تحتاج إلى توفير المخزن المؤقت الوجهة نفسها.الوجهة العازلة يجب أن تكون مجموعة شار العازلة.E. g.: char buffer[1024];

تأكد أن المعلمة الأولى لديه مساحة كافية لتخزين ما تحاول نسخ في ذلك.إذا كانت متاحة لك ، وهو أكثر أمانا من استخدام وظائف مثل: strcpy_s و strcat_s حيث كنت صراحة إلى تحديد حجم المخزن المؤقت الوجهة.

ملاحظة:سلسلة حرفية لا يمكن استخدامها كمنطقة عازلة ، لأنه هو ثابت.وهكذا أنت دائما يجب أن تخصص مجموعة شار المخزن المؤقت.

قيمة الإرجاع من strcat يمكن ببساطة تجاهل ذلك مجرد إرجاع نفس المؤشر كما صدر في الحجة الأولى.ومن هناك للراحة ، و يسمح لك سلسلة من المكالمات في سطر واحد من التعليمات البرمجية:

strcat(strcat(str, foo), bar);

حتى يمكن حل المشكلة على النحو التالي:

char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);

نصائح أخرى

وتجنب استخدام strcat في التعليمات البرمجية C. أنظف، والأهم من ذلك، أسلم طريقة هي استخدام snprintf :

char buf[256];
snprintf(buf, sizeof buf, "%s%s%s%s", str1, str2, str3, str4);

وأثار بعض المعلقين مسألة أن عددا من الحجج قد لا تتطابق مع سلسلة التنسيق ورمز سيظل ترجمة، ولكن معظم المجمعين تصدر بالفعل تحذيرا إذا كان هذا هو الحال.

الناس استخدام strncpy () ، شارعnالقط () ، أو قnprintf().
تجاوز المخزن المؤقت الخاص بك الفضاء القمامة ما يلي في الذاكرة!
(وتذكر أن تسمح مساحة زائدة null '\0' حرف!)

وأيضا malloc وrealloc مفيدة إذا كنت لا تعرف مسبقا كيف العديد من السلاسل يجري متسلسلة.

#include <stdio.h>
#include <string.h>

void example(const char *header, const char **words, size_t num_words)
{
    size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
    char *message = (char*) malloc(message_len);
    strncat(message, header, message_len);

    for(int i = 0; i < num_words; ++i)
    {
       message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
       message = (char*) realloc(message, message_len);
       strncat(strncat(message, ";", message_len), words[i], message_len);
    }

    puts(message);

    free(message);
}

ويمكن أيضا أن تكون متصلا سلاسل في وقت الترجمة.

#define SCHEMA "test"
#define TABLE  "data"

const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry =               // include comments in a string
    " SELECT * "                // get all fields
    " FROM " SCHEMA "." TABLE   /* the table */
    " WHERE x = 1 "             /* the filter */ 
                ;

لا تنس أن تهيئة المخزن المؤقت للإخراج. الحجة الأولى لstrcat يجب أن تكون فارغة إنهاء السلسلة مع مساحة إضافية كافية المخصصة للالسلسلة الناتجة:

char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string ); 
// null_terminated_string has less than 1023 chars

والوسيطة الأولى من strcat () يجب أن تكون قادرة على الاستمرار مساحة كافية لسلسلة متسلسلة. لذا تخصيص مخزن مؤقت مع مساحة كافية لتظهر النتيجة.

char bigEnough[64] = "";

strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);

/* and so on */

وstrcat () وسلسلة الوسيطة الثانية مع الوسيطة الأولى، وتخزين النتيجة في الوسيطة الأولى، وعاد شار * هو ببساطة هذه الحجة الأولى، وفقط من أجل راحتك.

وأنت لا تحصل على سلسلة المخصصة حديثا مع الأولى والثانية حجة متسلسلة، الذي كنت أعتقد أنك المتوقع استنادا إلى التعليمات البرمجية.

وكما أشار الناس من معالجة سلسلة تحسنت كثيرا. لذلك قد ترغب في معرفة كيفية استخدام المكتبة السلسلة C ++ بدلا من السلاسل على غرار C. ولكن هنا هو الحل في الخالص C

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void appendToHello(const char *s) {
    const char *const hello = "hello ";

    const size_t sLength     = strlen(s);
    const size_t helloLength = strlen(hello);
    const size_t totalLength = sLength + helloLength;

    char *const strBuf = malloc(totalLength + 1);
    if (strBuf == NULL) {
        fprintf(stderr, "malloc failed\n");
        exit(EXIT_FAILURE);
    }

    strcpy(strBuf, hello);
    strcpy(strBuf + helloLength, s);

    puts(strBuf);

    free(strBuf);

}

int main (void) {
    appendToHello("blah blah");
    return 0;
}

ولست متأكدا ما إذا كان من الصحيح / آمنة ولكن الآن لم أجد طريقة أفضل للقيام بذلك في ANSI C.

وأفضل طريقة للقيام بذلك دون وجود حجم المخزن المؤقت محدود عن طريق استخدام asprintf ()

char* concat(const char* str1, const char* str2)
{
    char* result;
    asprintf(&result, "%s%s", str1, str2);
    return result;
}

وإنه سلوك غير معرف في محاولة لتعديل سلسلة حرفية، وهو ما شيئا مثل:

strcat ("Hello, ", name);

وسوف تحاول أن تفعل. انها ستحاول تك على سلسلة name إلى نهاية "Hello, " الحرفي السلسلة، والذي لا يعرف أيضا.

وجرب شيئا هذا. ويحقق ما يبدو أن تحاول أن تفعل:

char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);

وهذا يخلق منطقة عازلة أن <م> هو السماح لتعديلها ثم نسخ كل من سلسلة حرفية وغيرها من النص على ذلك. فقط كن حذرا مع عازلة الفيضانات. إذا يمكنك التحكم في إدخال البيانات (أو التحقق من ذلك قبل اليد)، لا بأس في استخدام مخازن طول ثابتة مثل ولدي.

وعلى خلاف ذلك، يجب عليك استخدام استراتيجيات التخفيف مثل تخصيص ذاكرة كافية من كومة للتأكد من أنك قادرة على التعامل معها. وبعبارة أخرى، شيء من هذا القبيل:

const static char TEXT[] = "TEXT ";

// Make *sure* you have enough space.

char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
     handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);

// Need to free message at some point after you're done with it.

ويمكنك كتابة وظيفة بنفسك أن يفعل الشيء نفسه strcat() ولكن هذا لا يغير شيئا:

#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
    static char buffer[MAX_STRING_LENGTH];
    strncpy(buffer,str1,MAX_STRING_LENGTH);
    if(strlen(str1) < MAX_STRING_LENGTH){
        strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
    }
    buffer[MAX_STRING_LENGTH - 1] = '\0';
    return buffer;
}

int main(int argc,char *argv[]){
    printf("%s",strcat_const("Hello ","world"));    //Prints "Hello world"
    return 0;
}

وإذا كان كل من هم سلاسل معا أكثر من 1000 حرفا، فإنه سيتم قطع السلسلة في 1000 حرفا. يمكنك تغيير قيمة MAX_STRING_LENGTH لتناسب احتياجاتك.

على افتراض لديك شار[fixed_size] بدلا من شار* يمكنك استخدام واحدة, الإبداعية الكلية أن تفعل ذلك في كل مرة مع <<cout<<like يأمر ("بدلا %s مفككة %s ", "من" ، "printf نمط تنسيق").إذا كنت تعمل مع جزءا لا يتجزأ من نظم هذه الطريقة سوف تسمح لك أيضا أن تترك malloc و كبيرة *printf الأسرة من الوظائف مثل snprintf() (هذا يبقي dietlibc من تشكو *printf جدا)

#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
    char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
    const char *s, \
    *a[] = { __VA_ARGS__,NULL}, \
    **ss=a; \
    while((s=*ss++)) \
         while((*s)&&(++offset<(int)sizeof(buf))) \
            *bp++=*s++; \
    if (offset!=sizeof(buf))*bp=0; \
}while(0)

char buf[256];
int len=0;

strcpyALL(buf,len,
    "The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n"
);
if (len<sizeof(buf))
    write(1,buf,len); //outputs our message to stdout
else
    write(2,"error\n",6);

//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don't want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n");
if (len<sizeof(buf))
    write(1,buf,len); //outputs both messages
else
    write(2,"error\n",6);
  • ملاحظة 1 عادة لا تستخدم argv[0] هذا مجرد مثال
  • ملاحظة 2, يمكنك استخدام أي وظيفة أن مخرجات شار* ، بما في ذلك غير قياسي وظائف مثل itoa() لتحويل الأعداد الصحيحة إلى أنواع السلاسل.
  • ملاحظة 3, إذا كنت بالفعل باستخدام printf في أي مكان في البرنامج الخاص بك لا يوجد سبب لعدم استخدام snprintf () ، لأن التعليمات البرمجية المترجمة سيكون أكبر (ولكن inlined و بشكل أسرع)
int main()
{
    char input[100];
    gets(input);

    char str[101];
    strcpy(str, " ");
    strcat(str, input);

    char *p = str;

    while(*p) {
       if(*p == ' ' && isalpha(*(p+1)) != 0)
           printf("%c",*(p+1));
       p++;
    }

    return 0;
}

وأنت تحاول نسخ سلسلة إلى عنوان التي تم تخصيصها بشكل ثابت. تحتاج إلى القط إلى منطقة عازلة.

وعلى وجه التحديد:

... قص ...

وجهة

Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.

... قص ...

http://www.cplusplus.com/reference/clibrary/cstring /strcat.html

وهناك مثال هنا كذلك.

إذا كان لديك خبرة في C ستلاحظ أن سلاسل ليست سوى صفائف شار حيث الحرف الأخير هو حرف فارغة.

والآن بعد أن غير مريح تماما كما عليك أن تجد الحرف الأخير من أجل إلحاق شيء. سوف strcat نفعل ذلك لك.

وهكذا strcat عمليات البحث من خلال الوسيطة الأولى لحرف فارغة. ثم فإنه سيتم استبدال هذا مع محتوى الوسيطة الثانية في (حتى أن ينتهي في فارغة).

والآن دعونا نذهب من خلال التعليمات البرمجية:

message = strcat("TEXT " + var);

وهنا تقوم بإضافة شيء إلى المؤشر إلى النص "TEXT" (نوع "TEXT" هو حرف CONST * مؤشر).

وهذا عادة لا تعمل. تعديل ايضا ان "TEXT" مجموعة لا تعمل كما يتم وضعه عادة في قطعة ثابتة.

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));

وهذا قد تعمل على نحو أفضل، إلا أن تحاول مرة أخرى لتعديل النصوص الثابتة. strcat لا تخصيص ذاكرة جديدة للنتيجة.

وأود أن أقترح أن تفعل شيئا مثل هذا بدلا من ذلك:

sprintf(message2, "TEXT %s TEXT %s", foo, bar);

وقراءة وثائق من sprintf للتحقق من انها الخيارات.

والآن نقطة مهمة:

وتأكد من أن المخزن لديه مساحة كافية لاحتواء النص والطابع فارغة. وهناك زوجين من الوظائف التي يمكن أن تساعدك، على سبيل المثال، strncat وإصدارات خاصة من printf التي تخصص المخزن المؤقت بالنسبة لك. لا ضمان سوف حجم المخزن المؤقت يؤدي إلى تلف الذاكرة والبق استغلالها بعد.

وهذا هو بلدي الحل

#include <stdlib.h>
#include <stdarg.h>

char *strconcat(int num_args, ...) {
    int strsize = 0;
    va_list ap;
    va_start(ap, num_args);
    for (int i = 0; i < num_args; i++) 
        strsize += strlen(va_arg(ap, char*));

    char *res = malloc(strsize+1);
    strsize = 0;
    va_start(ap, num_args);
    for (int i = 0; i < num_args; i++) {
        char *s = va_arg(ap, char*);
        strcpy(res+strsize, s);
        strsize += strlen(s);
    }
    va_end(ap);
    res[strsize] = '\0';

    return res;
}

ولكن تحتاج لتحديد عدد سلاسل وأنت تسير لسلسلة

char *str = strconcat(3, "testing ", "this ", "thing");

وحاول شيئا مشابها لهذا:

#include <stdio.h>
#include <string.h>

int main(int argc, const char * argv[])
{
  // Insert code here...
  char firstname[100], secondname[100];
  printf("Enter First Name: ");
  fgets(firstname, 100, stdin);
  printf("Enter Second Name: ");
  fgets(secondname,100,stdin);
  firstname[strlen(firstname)-1]= '\0';
  printf("fullname is %s %s", firstname, secondname);

  return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top